2012-03-29 4 views
0

Ich schreibe eine etwas komplexe Spielengine in Android.Android: Update Thread verursacht GC eine Tonne laufen

Derzeit habe ich einen Thread zum Aktualisieren von Subsystemen verwendet.

Innerhalb der Update-Methode befindet sich die Methode zum Aktualisieren der Spiellogik, die auf dem aktuellen Spielstatus basiert.

Der Spielstatus hat eine Szene, die aktualisiert wird. Szenen bestehen aus einem Wurzelknoten, der eine einfache Szenengraphstruktur erzeugt.

Wurzeln sind Knoten, die Kinder haben, die auch aktualisiert werden und so weiter und so weiter.

Wie auch immer, das ist alles nett und dandy und funktioniert gut, bis ich eine Million davon in meinem Logcat: 03-29 09: 23: 22.866: D/dalvikvm (18554): GC_CONCURRENT befreit 511K, 52% kostenlos 2773K/5767K, externe 77K/587K, pausiert 2ms + 3ms

Ich habe die Ursache des Lecks als die Update-Schleife isoliert, als wenn ich meine Methode auskommentieren Subsysteme zu aktualisieren, gibt es keine GC-Nachrichten. Außerdem habe ich mich tief in die Update-Schleife und bis zu dem Punkt geäußert, an dem das Child-Update des Root-Knotens der Punkt ist, an dem der GC rasend schnell laufen würde.

(GameLgoic) 
public void onUpdate(float deltaTime) 
    { 
     if (gameState != null) 
      gameState.onUpdate(deltaTime); 
    } 
(GameState) 
public void onUpdate(float deltaTime) 
    { 
     scene.onUpdate(deltaTime); 
    } 
(Scene) 
public void onUpdate(float deltaTime) 
    { 
     root.onUpdate(deltaTime); 
    } 
(SceneNode) 
public void onUpdate(float deltaTime) 
    { 
     for (int i = 0; i < children.size(); ++i) 
     { 
      children.get(i).onUpdate(deltaTime); // Memory leak runs crazily here 
     } 
    } 

Wenn ich children.get (i) auf Kommentar .onUpdate (DELTA) Es gibt keine Lecks! Mein Verstand ist so verblüfft. Danke Leute.

+1

gute Nachricht: Ihr Leck nicht die onUpdate() -Aufruf ist. Es ist der Code, der in dieser Methode enthalten ist. Bitte fügen Sie die entsprechenden Code-Snippets hinzu. – WarrenFaith

+1

Bitte zeigen Sie die Definition von 'Kinder' und die dazugehörige' OnUpdate' Methode an. – Gray

+2

Oh, und jedes Mal, wenn Sie 'size()' in einer Schleife aufrufen, stirbt ein Kätzchen. Sie sollten die Leistungsbeschreibung in der offiziellen Dokumentation überprüfen :) – WarrenFaith

Antwort

2

Ich stieß auf ähnliches Problem, wenn ich ein Spiel für Android machte. Der einzige Weg, um hier rauszukommen, ist Embedded-C-Style zu programmieren. Wenn Sie also eine Schleife möchten, Ihre Zählvariable wiederzuverwenden, sowie Ihre Begrenzungs Variable, wann immer möglich, etwa so:

int i; 
int max 
void loop(){ 
    max = bla.size(); 
    for(i=0; i<max; i++){ ... } 
} 

Das gleiche gilt für buchstäblich alles, was Sie berühren. Sie könnten also erwägen, Verweise auf Objekte, die Sie nicht mehr benötigen, zu behalten und sie später wiederzuverwenden.

Es ist verrückt, welchen Unterschied es zu meinem Spiel gemacht hat, diese Änderungen zu implementieren. Framerate verdoppelt, enorme Reduzierung von Verzögerungen und so weiter.

Sie sollten in das DDMS-Tool schauen, welches das Eclipse Android SDK liefert. Sie können damit Zuordnungen aufspüren, um diese Probleme zu vermeiden.

Zusätzlich sollten Sie alle Interaktoren entfernen, da sie jedes Mal zugewiesen werden, wenn Sie in eine Schleife springen und nicht wiederverwendet werden können. Daher ist es besser, manuell eine Schleife zu erstellen und mehrmals durch Ihre Listen zu gehen (get(x) in Schleife), als auf lange Sicht auf den Garbage Collector warten zu müssen.

+0

gute Verbesserung, aber wie er sagte 'Wenn ich auskommen children.get (i) .onUpdate (deltaTime) Es gibt keine Lecks!' Die Ursache scheint im Code dieser Methode zu sein, nicht die Schleife selbst ... – WarrenFaith

+0

in diesem Fall könnte die Syntax 'für (Kind c: Kinder) 'auch praktisch sein. – Jave

+0

Ich habe gerade meine Antwort erweitert, um auch dies zu erfassen: Iteratoren werden auch Objekte sein, die vom GC gesammelt werden, also ist das leider keine Option. – devsnd

0

Zuerst zur Klärung der Terminologie - Sie nicht haben a memory leak. Ein Speicherverlust tritt auf, wenn die Speichernutzung Ihrer App wächst und wächst, da sie nicht mehr den Speicher freigibt, den sie nicht mehr verwendet. Sie haben die gegenüber Problem - Sie veröffentlichen eine Menge ungenutzten Speicher, der garbage collected sein muss.

Freigeben von ungenutztem Speicher ist normalerweise eine gute Sache; Es wird nur ein Problem, wenn die Garbage Collection, die zum Bereinigen des freigegebenen Speichers erforderlich ist, Leistungsprobleme verursacht, die Sie hier sehen.

Es gibt nichts Schlimmeres mit dem Code, den Sie bisher gepostet haben.Das Problem scheint innerhalb der onUpdate() Methode zu liegen, so dass Sie den Code dafür schreiben könnten.

Im Allgemeinen können Sie Garbage Collections reduzieren, indem Sie Objekte wo möglich wiederverwenden, anstatt sie zu zerstören und zu erstellen.

Schließlich ist ein kleiner Punkt, können Sie ersetzen:

for (int i = 0; i < children.size(); ++i) 
{ 
    children.get(i).onUpdate(deltaTime); // Memory leak runs crazily here 
} 

mit a for loop:

for (SomeClass child : children) { 
    child.onUpdate(deltaTime); 
} 
+0

Ich gebe es in einem Stück! Danke Kumpel. – DubyaDubyaDubyaDot

Verwandte Themen