Müllsammler in Android

108

Ich habe viele Android-Antworten gesehen, die vorschlagen, in einigen Situationen den Garbage Collector anzurufen.

Ist es eine gute Praxis, den Garbage Collector in Android anzufordern, bevor eine speicherhungrige Operation ausgeführt wird? Wenn nicht, sollte ich es nur anrufen, wenn ich eine OutOfMemoryFehlermeldung erhalte ?

Gibt es andere Dinge, die ich verwenden sollte, bevor ich auf den Müllsammler zurückgreife?

hpique
quelle

Antworten:

144

Für Versionen vor 3.0 Honeycomb : Ja, rufen Sie an System.gc() .

Ich habe versucht, Bitmaps zu erstellen, habe aber immer "VM out of memory error" erhalten. Aber als ich System.gc()zuerst anrief, war es in Ordnung.

Beim Erstellen von Bitmaps schlägt Android häufig mit Speicherfehlern fehl und versucht nicht, zuerst die Speicherbereinigung durchzuführen . Rufen System.gc()Sie daher an, und Sie haben genügend Speicher, um Bitmaps zu erstellen.

Wenn Sie Objekte erstellen, werden diese meiner Meinung System.gcnach bei Bedarf automatisch aufgerufen, jedoch nicht zum Erstellen von Bitmaps. Es scheitert einfach.

Ich empfehle daher, System.gc()vor dem Erstellen von Bitmaps manuell aufzurufen .

Steve
quelle
39
Dies liegt daran, dass Bitmap-Daten vor der Wabe nicht in der VM gespeichert sind und daher den GC nicht auslösen. In Honeycomb und später sollte es kein Problem sein.
Timmmm
2
@Timmmm aber es war eigentlich mein Problem, ich habe nur largeheap auf true gesetzt.
Lei Leyba
118

Im Allgemeinen ist es in Gegenwart eines Garbage Collectors niemals empfehlenswert, den GC manuell aufzurufen. Ein GC basiert auf heuristischen Algorithmen, die am besten funktionieren, wenn sie sich selbst überlassen bleiben. Das manuelle Aufrufen des GC verringert häufig die Leistung.

In einigen relativ seltenen Situationen kann es gelegentlich vorkommen , dass ein bestimmter GC einen Fehler macht, und ein manueller Aufruf des GC kann dann die Leistung verbessern. Dies liegt daran, dass es nicht wirklich möglich ist, einen "perfekten" GC zu implementieren, der den Speicher in allen Fällen optimal verwaltet. Solche Situationen sind schwer vorherzusagen und hängen von vielen subtilen Implementierungsdetails ab. Die "gute Praxis" besteht darin, den GC von selbst laufen zu lassen; Ein manueller Aufruf an den GC ist die Ausnahme, die erst in Betracht gezogen werden sollte, nachdem ein tatsächliches Leistungsproblem ordnungsgemäß festgestellt wurde.

Thomas Pornin
quelle
8
+1 für eine gute plattformunabhängige Antwort. Warten Sie, bis Sie eine Android-spezifische Antwort gefunden haben, bevor Sie sich entscheiden.
Hpique
8
Ich stimme dem zu, was Sie geschrieben haben, wenn Sie zulassen, dass "Leistung" etwas allgemeineres als die CPU-Effizienz bedeutet. Auf einem Android-Gerät ist die Wahrnehmung der Leistung durch den Benutzer von größter Bedeutung. Der Entwickler kann es vorziehen, den GC auszuführen, während der Benutzer beispielsweise Tasten drückt, damit der Benutzer den GC nicht kennt.
Präsident James K. Polk
5
In Spielen ist es oft wichtig, dass der GC nicht ausgeführt wird, während das Spiel ausgeführt wird (dies erfordert, dass alle Objekte vorab erstellt und recycelt wurden oder ähnlich), aber wenn das Spiel angehalten wird, ist es ein guter Zeitpunkt für den GC.
Pat
4
Bitmap-Daten vor der Wabe werden nicht im VM-Speicher gespeichert. Das System erkennt nicht, wenn Sie aufgrund von Bitmaps zu viel Nicht-VM-Speicher verwendet haben, und führt den GC aus (wodurch die Bitmap.finalize()Methoden ausgeführt werden, die den Nicht-VM-Speicher freigeben). Daher wird in diesem Fall, Sie sollten die GC Kopf und laufen gehen Bitmap.recycle()oder System.gc()gegebenenfalls. Aber nur vor der Wabe.
Timmmm
1
@ThomasPornin - Andererseits wissen Sie als Anwendungsprogrammierer etwas, das das Betriebssystem nicht kennt: Zeiten, in denen Ihre App jetzt eine wesentliche Änderung in der Verwendung des Speichers vornehmen wird und die weniger störend wäre Die Benutzererfahrung macht jetzt eine Pause, als zu einem beliebigen Zeitpunkt in der Zukunft . Dies bedeutet, dass es möglicherweise sinnvoll ist , bei wichtigen Übergängen bei der Verwendung der App selten Anrufe zu tätigen . Diese sind in dem Sinne selten, dass man GC nicht häufig anrufen sollte, aber sie sind insofern üblich , als fast jede bedeutende App solche vom Design her bekannten Momente aufweist.
ToolmakerSteve
26

Nicht genügend Speicher in Android-Anwendungen ist sehr häufig, wenn wir die Bitmap nicht richtig behandeln. Die Lösung für das Problem wäre

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

Im obigen Code habe ich gerade versucht, die Bitmap zu recyceln, mit der Sie den verwendeten Speicherplatz freigeben können, sodass möglicherweise nicht genügend Speicherplatz zur Verfügung steht. Ich habe versucht, dass es bei mir funktioniert.

Wenn das Problem weiterhin besteht, können Sie diese Zeile auch hinzufügen

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

Weitere Informationen finden Sie unter diesem Link

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


HINWEIS: Aufgrund der kurzzeitigen "Pause", die durch die Ausführung von gc verursacht wird, wird nicht empfohlen, dies vor jeder Bitmap-Zuweisung zu tun .

Optimales Design ist:

  1. Geben Sie alle nicht mehr benötigten Bitmaps mit dem if / recycle / nullangezeigten Code frei. (Machen Sie eine Methode, um dabei zu helfen.)

  2. System.gc();

  3. Ordnen Sie die neuen Bitmaps zu.

Yogesh
quelle
19

Wenn Sie einen OutOfMemoryError erhalten, ist es normalerweise zu spät, den Garbage Collector aufzurufen ...

Hier ist ein Zitat von Android Developer:

In den meisten Fällen erfolgt die Speicherbereinigung aufgrund von Tonnen kleiner, kurzlebiger Objekte, und einige Speicherbereinigungsprogramme, wie z. B. Speicherbereinigungsprogramme für Generationen, können die Erfassung dieser Objekte optimieren, damit die Anwendung nicht zu oft unterbrochen wird. Der Android-Garbage-Collector kann solche Optimierungen leider nicht durchführen, und die Erstellung kurzlebiger Objekte in leistungskritischen Codepfaden ist daher für Ihre Anwendung sehr kostspielig.

Nach meinem Verständnis besteht also keine dringende Notwendigkeit, den GC anzurufen. Es ist besser, mehr Aufwand zu betreiben, um die unnötige Erstellung von Objekten zu vermeiden (wie die Erstellung von Objekten in Schleifen).

Andreas Dolk
quelle
6
Kann das Zitat nicht anders interpretiert werden? Möglicherweise muss der GC manuell aufgerufen werden, um diese Objekte zu sammeln, bevor sie zu viel Speicher verbrauchen.
Hpique
@hgpc: Ich sehe nicht, wie das Zitat so interpretiert werden kann, wie Sie es vorschlagen. Ich vermute, die Dokumentation ist ein Geständnis und gibt zu, dass ihre GC einfach ist. Wenn der Speicher knapp wird, wird ein vollständiger GC ausgeführt.
Präsident James K. Polk
Die vollständige Nutzung komplexer Objekte und Frameworks mit komplexen Objekten nutzt die Entwicklungszeit tendenziell besser als die vorzeitige Optimierung. Die Sorge um die Optimierung ist für Android eine leichtere Falle als für Enterprise Java, da wir beim Codieren einer mobilen App unbewusst über die Leistung nachdenken. Vor allem , da dem Rahmen - Entwickler, die haben über die Leistung zu denken, Leck , dass die Sicht in die offizielle Dokumentation , wenn sie nicht vorsichtig sind.
LateralFractal
9

Es scheint System.gc()nicht auf Art Android 6.0.1 Nexus 5x zu funktionieren, also benutze ich Runtime.getRuntime().gc();stattdessen.

cmicat
quelle
1
System.gc()ist eine Wrapper-Funktion für Runtime.getRuntime().gc(). Siehe android.googlesource.com/platform/libcore/+/…
Nathan F.
Ja, aus Quelle und Dokumentation sieht es so aus, als wären sie gleich, System.gc()funktioniert aber bei mir zwar nicht, Runtime.getRuntime().gc()tut es aber !
Ivan vor
7

Meine App verwaltet viele Bilder und ist mit einem OutOfMemoryError gestorben. Das hat mir geholfen. In der Manifest.xml hinzufügen

<application
....
   android:largeHeap="true"> 
Klykoo
quelle
9
Google mag das nicht
Pedro Paulo Amorim
1
@ PedroPauloAmorim erklären warum?
Machado
2
Verwenden Sie largeHeap nur, wenn Sie sicher sind, was Sie tun. Durch die Verwendung großer Heaps arbeitet der Garbage Collector viel härter, da er viele Junk-Daten durchlaufen muss, bevor der Speicher gelöscht wird.
Prakash
7

Im Allgemeinen sollten Sie GC nicht explizit mit System.gc () aufrufen. Es gibt sogar die IO-Vorlesung ( http://www.youtube.com/watch?v=_CruQY55HOk ), in der erklärt wird, was das GC-Pausenprotokoll bedeutet und in der sie auch angeben, niemals System.gc () aufzurufen, weil Dalvik es besser weiß als Sie, wenn Sie dies tun.

Andererseits ist, wie in den obigen Antworten erwähnt, der GC-Prozess in Android (wie alles andere auch) manchmal fehlerhaft. Dies bedeutet, dass Dalvik GC-Algorithmen nicht mit Hotspot- oder JRockit-JVMs vergleichbar sind und in einigen Fällen Fehler verursachen können. Eine dieser Gelegenheiten ist das Zuweisen von Bitmap-Objekten. Dies ist schwierig, da es Heap- und Nicht-Heap-Speicher verwendet und eine lose Instanz eines Bitmap-Objekts auf einem Gerät mit eingeschränktem Speicher ausreicht, um eine OutOfMemory-Ausnahme auszulösen. Wenn Sie diese Bitmap nicht mehr benötigen, wird dies von vielen Entwicklern im Allgemeinen empfohlen und von einigen sogar als bewährte Methode angesehen.

Besser ist es, .recycle () für eine Bitmap zu verwenden, da dies das Ziel dieser Methode ist, da der native Speicher der Bitmap als sicher zum Löschen markiert wird. Beachten Sie, dass dies sehr versionierungsabhängig ist, was bedeutet, dass es im Allgemeinen für ältere Android-Versionen (Pre 3.0, glaube ich) erforderlich ist, für spätere jedoch nicht. Es wird auch nicht viel schaden, wenn man es auf neueren Ether-Versionen verwendet (mach das einfach nicht in einer Schleife oder so). Die neue ART-Laufzeit hat sich hier stark verändert, da sie eine spezielle Heap- "Partition" für große Objekte eingeführt hat, aber ich denke, es wird nicht viel schaden, dies mit ART Ether zu tun.

Auch ein sehr wichtiger Hinweis zu System.gc (). Diese Methode ist kein Befehl, auf den Dalvik (oder JVMs) reagieren müssen. Betrachten Sie es eher so, als würden Sie der virtuellen Maschine sagen: "Könnten Sie bitte die Speicherbereinigung durchführen, wenn dies kein Problem ist?".

Igor Čordaš
quelle
3

Ich würde nein sagen, da der Entwickler den RAM-Nutzungsstatus dokumentiert:

...
GC_EXPLICIT

Eine explizite GC, wie Sie bei einem Anruf gc () (die Sie sollten vermeiden , fordern und stattdessen den GC vertrauen zu laufen , wenn erforderlich).

...

Ich habe den relevanten Teil fett hervorgehoben.

Schauen Sie sich die YouTube-Serie " Android Performance Patterns" an. Dort finden Sie Tipps zum Verwalten der Speichernutzung Ihrer App (z. B. zur Verwendung von ArrayMaps und SparseArrays von Android anstelle von HashMaps).

Farbod Salamat-Zadeh
quelle
3

Kurzer Hinweis für Xamarin-Entwickler .

Wenn Sie System.gc()Xamarin.Android-Apps aufrufen möchten, sollten Sie anrufenJava.Lang.JavaSystem.Gc()

Denis Gordin
quelle
2

Es ist nicht erforderlich, den Garbage Collector nach einem aufzurufen OutOfMemoryError.

Es ist Javadoc klar gesagt:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

Der Garbage Collector hat also bereits versucht, Speicher freizugeben, bevor der Fehler generiert wurde, war jedoch nicht erfolgreich.

perdian
quelle
8
Das Android Javadoc gibt dies nicht an, und höchstwahrscheinlich ist seine Implementierung anders. d.android.com/reference/java/lang/OutOfMemoryError.html
hpique
Sie haben Recht, dass dies unter Android nicht gilt. Aber andererseits können Sie OOE zur Laufzeit nicht verarbeiten, so dass Sie nicht viel dagegen tun können, selbst wenn dies wahr war / nicht wahr war.
Igor Čordaš