Um den JNI zu verwenden oder den JNI nicht zu verwenden (Android-Leistung)

9

Ich habe gerade einen rechenintensiven Code zu einem Android-Spiel hinzugefügt, das ich gerade entwickle. Der fragliche Code ist eine Sammlung von Kollisionserkennungsroutinen, die sehr oft aufgerufen werden (jede Iteration der Spielschleife) und eine große Menge an Berechnungen durchführen. Ich habe das Gefühl, dass meine Kollisionserkennungsimplementierung ziemlich gut entwickelt ist und so schnell, wie ich es in Java machen kann.

Ich habe Traceview verwendet, um den Code und dieses neue Stück zu profilieren der Kollisionserkennungscode hat die Dauer meiner Spiellogik etwas überraschend verdoppelt. Das ist offensichtlich ein Problem, da dieser Performance-Hit für bestimmte Geräte mein Spiel von einem spielbaren in einen unspielbaren Zustand versetzen könnte.

Ich habe verschiedene Möglichkeiten erwogen, diesen Code zu optimieren, und ich frage mich, ob, wenn ich den Code in C ++ verschiebe und mit dem JNI darauf zugreife, wenn ich merkliche Leistungseinsparungen erhalte?

Die obige Frage ist mein Hauptanliegen und mein Grund zu fragen. Ich habe festgestellt, dass die beiden folgenden Gründe andere positive Ergebnisse bei der Verwendung des JNI wären. Es ist jedoch nicht genug, um mich zu überreden, meinen Code nach C ++ zu portieren.

  • Dies würde den Code sauberer machen. Da der Großteil der Kollisionserkennung eine Art von Vektormathematik ist, ist es viel sauberer, in der Lage zu sein, überladene Operatoren zu verwenden, anstatt in Java ausführlichere Vektorklassen zu verwenden.

  • Die Speicherverwaltung wäre einfacher. Einfacher, sagst du? Nun, das ist ein Spiel, daher ist der laufende Garbage Collector nicht willkommen, weil der GC die Performance Ihres Spiels ruinieren könnte, wenn er ständig unterbrochen werden muss, um aufzuräumen. In C muss ich mich nicht um den Garbage Collector kümmern, so dass ich all die hässlichen Dinge vermeiden kann, die ich in Java mit temporären statischen Variablen mache und nur auf den guten alten Stackspeicher von C ++

  • angewiesen bin

Langweilig, wie diese Frage sein mag, ich denke, ich habe alle meine Punkte abgedeckt. Wäre es angesichts dieser Informationen sinnvoll, meinen Code von Java nach C ++ zu portieren und mit dem JNI darauf zuzugreifen (aus Gründen der Leistungsverbesserung)? Gibt es auch eine Möglichkeit, einen potenziellen Leistungszuwachs zu messen oder zu schätzen?

BEARBEITEN:

Also habe ich es getan. Ergebnisse? Nun, aus der Sicht von TraceView war es eine 6-fache Steigerung der Geschwindigkeit meiner Kollisionserkennungsroutine.

Es war jedoch nicht einfach, dorthin zu gelangen. Neben dem JNI-Tanz musste ich auch einige Optimierungen vornehmen, die ich nicht erwartet hatte. Hauptsächlich Verwendung eines direkt zugewiesenen Float-Puffers, um Daten von Java an Native zu übergeben. Mein erster Versuch verwendete nur ein Float-Array, um die Daten in Frage zu halten, da die Konvertierung von Java nach C ++ natürlicher war, aber das war wirklich langsam. Der direkte Puffer hat Performance-Probleme beim Array-Kopieren zwischen Java und nativ komplett umgangen und mich mit einem 6x-Bump zurückgelassen.

Außerdem habe ich, anstatt meine eigene Vektorklasse zu rollen, nur die Eigen Math Bibliothek benutzt. Ich bin mir nicht sicher, welchen Einfluss dies auf die Performance hatte, aber zumindest rettete es mir die Zeit, meine eigene (weniger effiziente) Vektorklasse zu entwickeln.

Eine weitere Lektion, die wir gelernt haben, ist, dass eine übermäßige Protokollierung für die Performance schlecht ist (jic, die nicht offensichtlich ist).

    
user8709 27.01.2012, 10:00
quelle

2 Antworten

4

Nicht wirklich eine direkte Antwort auf Ihre Frage, aber die folgenden Links könnten für Sie von Nutzen sein:

Im zweiten Link wird folgendes geschrieben:

  

Nativer Code ist nicht unbedingt effizienter als Java. Für eine Sache,   Der Java-native Übergang und das JIT sind mit Kosten verbunden   kann über diese Grenzen hinweg nicht optimieren. Wenn Sie Native zuweisen   Ressourcen (Speicher auf dem nativen Heap, Dateideskriptoren oder was auch immer),   es kann wesentlich schwieriger sein, rechtzeitige Abholung zu organisieren   diese Ressourcen. Sie müssen auch Ihren Code für jeden kompilieren   Architektur, auf der Sie laufen möchten (anstatt sich darauf zu verlassen, dass es eine JIT hat).   Sie müssen sogar mehrere Versionen für das, was Sie in Betracht ziehen, kompilieren   die gleiche Architektur: Native Code für den ARM-Prozessor in kompiliert   Das G1 kann den ARM im Nexus One und Code nicht voll ausnutzen   kompiliert für den ARM im Nexus One wird nicht auf dem ARM im G1 laufen.

     

Nativer Code ist in erster Linie nützlich, wenn Sie einen vorhandenen nativen Code haben   Codebase, die Sie auf Android portieren möchten, nicht zum "Beschleunigen" von Teilen   einer Java-App.

    
Jave 27.01.2012, 10:11
quelle
1

Wenn Sie sich noch in einer relativ frühen Phase der Spieleentwicklung befinden, können Sie eine Game Engine in Erwägung ziehen, die einen guten Kollisionserkennungsmechanismus bietet, wie Libgdx, der die Box2D Kollisionserkennung recht gut macht.

    
Arun Singh 01.02.2012 11:27
quelle