Eine Einführung in die Speicherverwaltung und Speicherlecks unter Android

Es ist zu bedenken, dass dieses Tool zwar sehr nützlich sein kann, um Verweise auf ein vermutetes Leck zu finden, dass es aber ziemlich schwierig und komplex sein kann, um unbekannte Lecks zu finden, und dass es ein gutes Stück Analyse erfordert. Wenn man es jedoch beherrscht, ist es ein großartiges Werkzeug, das man in der Tasche haben sollte!

LeakCanary

Bild von LeakCanary

Eine weitere Möglichkeit, Speicherlecks zu finden, ist die Verwendung von Leak Canary, einer von Square erstellten Bibliothek, die dabei hilft, Speicherlecks zu erkennen. Sie arbeitet mit einer ObjectWatcher Klasse, die schwache Referenzen auf zerstörte Objekte im Heap hält. Wird die Referenz nicht innerhalb der nächsten fünf Sekunden gelöscht und der Garbage Collector läuft, gilt das Objekt als erhalten und protokolliert dies als mögliches Speicherleck im Logcat. Ziemlich clever, oder?

Um loszulegen, fügen Sie einfach die Bibliothek innerhalb der Abhängigkeiten zu Ihrer build.gradle-Datei hinzu, synchronisieren und kompilieren.

Fügen Sie die LeakCanary-Bibliothek hinzu

Sobald Sie die Anwendung starten, können Sie die Ausgabe von LeakCanary im Logcat sehen, da es Instants beobachtet und Objekte zurückhält. Um ein Leck auszulösen, fügte ich ein paar neue Aufgaben in meiner TaskManager-Anwendung hinzu. Kurze Zeit später erhielt ich diese Benachrichtigung von LeakCanary, die auf ein potenzielles Leck hinweist!

Klicken Sie einfach auf die Benachrichtigung „dump heap“, um das potenzielle Leck zu untersuchen und dieser Dialog wird in der App angezeigt.

LeakCanary untersucht die Lecks ..

Leak Canary analysiert dann den Heap durch Auffinden der zurückgehaltenen Objekte und findet die Leckspur, die ein Pfad von Referenzen zu jedem zurückgehaltenen Objekt ist. Sobald dies geschehen ist, wird eine Benachrichtigung angezeigt, die die Anzahl der zurückgehaltenen Objekte und Lecks zusammenfasst.

Sieht aus, als hätte es unser Leck gefunden! Wenn wir darauf klicken, sehen wir die vollständige Leckspur:

Sie sagt uns, dass TaskActivity ein Leck hat, und die unterstrichenen Verweise zeigen die Spur, es ist ein Leck von mContext in SingletonExample – klingt vertraut! Jetzt wissen wir, wie wir ein Leck mit LeakCanary finden können. 😃

Speicherlecks vermeiden

So, jetzt haben wir unser Speicherleck gefunden, wie können wir es in Zukunft vermeiden? Im Folgenden finden Sie einige der häufigsten Ursachen und Muster.

Foto von Bogomil Mihaylov auf Unsplash

Broadcast-Empfänger

Broadcast-Empfänger können verwendet werden, um auf systemweite Broadcast-Ereignisse oder Intents zu hören, die Geräteinformationen wie einen niedrigen Batteriestand anzeigen, Datum und Konnektivitätsänderungen – zum Beispiel, dass der Flugzeugmodus ausgeschaltet wurde. Wenn man sie verwendet, muss man daran denken, die Registrierung von Broadcast-Empfängern aufzuheben, da man sonst unweigerlich einen Verweis auf die Aktivität behält.

Wie man das vermeiden kann: Alles, was Sie tun müssen, ist, unregister() auf Ihrem Broadcast-Empfänger in onStop() in Ihrer Aktivität aufzurufen.

Dieses Muster findet sich auch bei asyncTask, TimerTask und Threads, die in onDestroy() abgebrochen werden müssen, um ein Leck zu vermeiden.

Kontext zu Singleton-Klasse

Manchmal müssen wir Kontext von einer Aktivität an eine Singleton-Klasse übergeben. Ein Beispiel hierfür wäre eine utils-Klasse, die auf Ressourcen, Dienste oder interne Dateien zugreifen muss. Die Übergabe von Kontext bedeutet jedoch, dass wir unweigerlich einen Verweis auf die Aktivität behalten.

Wie man dies vermeiden kann: Anstatt this von einer Aktivität zu übergeben, können wir den Anwendungskontext übergeben, wenn er verfügbar ist (wenn Sie mehr darüber erfahren möchten, wann Sie welchen Kontext verwenden sollten, fand ich diesen Artikel sehr hilfreich!). Eine alternative Lösung besteht darin, den Singleton-Kontext innerhalb der onDestroy()-Methode der Aktivität auf null zu setzen.

Statische Referenzen

Eine Ansicht oder eine Aktivität als statisch zu referenzieren bedeutet, dass die Referenz auf die Aktivität nicht in den Müll wandert. Dies sollte einfach immer vermieden werden.

Wie man es vermeiden kann: Wenn Sie es aus irgendeinem Grund tun müssen, können Sie sicherstellen, dass es zerstört wird, indem Sie es auf null setzen in onDestroy().

Inner class references

Inner classes often cause leaks by holding an implicit reference to the outer class. Dies geschieht, wenn die Klassenvariable als statisch deklariert ist oder wenn die Klasse selbst nicht als statisch deklariert ist. Verwirrend? Ja, aber es ist leicht zu vermeiden, wenn wir die folgende einfache Regel befolgen.

Wie man es vermeidet: Machen Sie die innere Klasse statisch, um eine Referenz auf die äußere Klasse zu vermeiden, und erstellen Sie niemals eine statische Variable einer inneren Klasse. Das gleiche gilt für anonyme Klassen.

Das war’s! Ich hoffe, Sie haben etwas über Speicherlecks gelernt und wie man sie vermeiden kann. Viel Spaß beim Programmieren! 😄

Hier sind eine Reihe von Artikeln und Dokumentationen, die ich besonders nützlich fand, als ich über Speicherlecks lernte:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.