Heap-Dump erfassen

Mit einem Heap-Dump können Sie sehen, welche Objekte in Ihrer App zum Zeitpunkt der Erfassung Arbeitsspeicher belegen, und Speicherlecks oder Arbeitsspeicherzuweisungsverhalten erkennen, das zu Ruckeln, Einfrieren und sogar App-Abstürzen führt. Es ist besonders hilfreich, Heap-Dumps nach einer längeren Nutzersitzung zu erstellen, da sie Objekte zeigen können, die sich noch im Arbeitsspeicher befinden, obwohl sie dort nicht mehr sein sollten.

Auf dieser Seite wird beschrieben, welche Tools Android Studio zum Erfassen und Analysieren von Heap-Dumps bietet. Alternativ können Sie den Arbeitsspeicher Ihrer App über die Befehlszeile mit dumpsys untersuchen und Ereignisse zur automatischen Speicherbereinigung (GC) in Logcat ansehen.

Gründe für das Profiling des Arbeitsspeichers Ihrer App

Android bietet eine Umgebung mit verwaltetem Arbeitsspeicher. Wenn Android feststellt, dass Ihre App bestimmte Objekte nicht mehr verwendet, gibt die Garbage Collection den nicht verwendeten Arbeitsspeicher wieder an den Heap zurück. Die Suche nach ungenutztem Speicher wird in Android ständig verbessert. In allen Android-Versionen muss das System Ihren Code jedoch irgendwann kurz unterbrechen. Meistens sind die Pausen nicht wahrnehmbar. Wenn Ihre App jedoch schneller Arbeitsspeicher zuweist, als das System ihn erfassen kann, kann es zu Verzögerungen kommen, während der Collector genügend Arbeitsspeicher freigibt, um Ihre Zuweisungen zu erfüllen. Die Verzögerung kann dazu führen, dass in Ihrer App Frames übersprungen werden und sie sichtbar langsam ist.

Auch wenn Ihre App nicht langsam ist, kann sie Arbeitsspeicher belegen, wenn sie Arbeitsspeicherlecks aufweist, selbst wenn sie im Hintergrund ausgeführt wird. Dieses Verhalten kann die Speicherleistung des restlichen Systems verlangsamen, da unnötige automatische Speicherbereinigungs-Vorgänge erzwungen werden. Schließlich muss das System den App-Prozess beenden, um den Speicher freizugeben. Wenn der Nutzer dann zu Ihrer App zurückkehrt, muss der App-Prozess vollständig neu gestartet werden.

Informationen zu Programmierpraktiken, mit denen der Speicherverbrauch Ihrer App reduziert werden kann, finden Sie unter Verwaltung Ihres App-Speichers.

Heap-Dump-Übersicht

Um einen Heap-Dump zu erfassen, wählen Sie die Aufgabe Speichernutzung analysieren (Heap-Dump) aus (verwenden Sie Profiler: run 'app' as debuggable (complete data)). Beim Dumping des Heaps kann die Menge des Java-Speichers vorübergehend ansteigen. Das ist normal, da der Heap-Dump im selben Prozess wie Ihre App erfolgt und zum Erfassen der Daten etwas Arbeitsspeicher benötigt wird. Nachdem Sie den Heap-Dump erfasst haben, sehen Sie Folgendes:

Die Ansicht „Heap Dump“ im Android Studio Profiler

Die Liste der Kurse enthält die folgenden Informationen:

  • Zuweisungen: Anzahl der Zuweisungen im Heap.
  • Native Size (Native Größe): Die Gesamtmenge des nativen Speichers, der von diesem Objekttyp verwendet wird (in Byte). Hier sehen Sie Arbeitsspeicher für einige in Java zugewiesene Objekte, da Android nativen Arbeitsspeicher für einige Framework-Klassen wie Bitmap verwendet.

  • Shallow Size (Flache Größe): Die Gesamtmenge des von diesem Objekttyp verwendeten Java-Speichers (in Byte).

  • Beibehaltener Speicher: Die Gesamtgröße des Arbeitsspeichers, der aufgrund aller Instanzen dieser Klasse beibehalten wird (in Byte).

Über das Heap-Menü können Sie nach bestimmten Heaps filtern:

  • App-Heap (Standard): Der primäre Heap, auf dem Ihre App Speicher zuweist.
  • Image-Heap: Das System-Boot-Image mit Klassen, die während des Bootvorgangs vorab geladen werden. Zuweisungen werden hier nie verschoben oder entfernt.
  • Zygote-Heap: Der Copy-on-Write-Heap, aus dem ein App-Prozess im Android-System verzweigt wird.

Wählen Sie im Drop-down-Menü „Anordnung“ aus, wie die Zuweisungen angeordnet werden sollen:

  • Nach Klasse anordnen (Standard): Alle Zuweisungen werden nach Klassennamen gruppiert.
  • Nach Paket anordnen: Alle Zuweisungen werden nach Paketname gruppiert.

Verwenden Sie das Drop-down-Menü für Kurse, um nach Kursgruppen zu filtern:

  • Alle Klassen (Standard): Hier werden alle Klassen angezeigt, einschließlich der Klassen aus Bibliotheken und Abhängigkeiten.
  • Show activity/fragment leaks (Aktivitäts-/Fragment-Leaks anzeigen): Zeigt Klassen an, die Speicherlecks verursachen.
  • Projektklassen anzeigen: Hier werden nur die von Ihrem Projekt definierten Klassen angezeigt.

Klicken Sie auf einen Klassennamen, um den Bereich Instanz zu öffnen. Jede aufgeführte Instanz enthält Folgendes:

  • Tiefe: Die kürzeste Anzahl von Hops von einem beliebigen GC-Root zur ausgewählten Instanz.
  • Native Size (Native Größe): Größe dieser Instanz im nativen Speicher. Diese Spalte ist nur für Android 7.0 und höher sichtbar.
  • Shallow Size: Größe dieser Instanz im Java-Arbeitsspeicher.
  • Beibehaltene Größe: Größe des Arbeitsspeichers, den diese Instanz dominiert (gemäß dem Dominator-Baum).

Klicken Sie auf eine Instanz, um die Instanzdetails einschließlich der Felder und Referenzen aufzurufen. Gängige Feld- und Referenztypen sind strukturierte Typen , Arrays und primitive Datentypen in Java. Klicken Sie mit der rechten Maustaste auf ein Feld oder eine Referenz, um zur zugehörigen Instanz oder Zeile im Quellcode zu gelangen.

  • Felder: Hier werden alle Felder in dieser Instanz angezeigt.
  • Referenzen: Hier werden alle Referenzen auf das Objekt angezeigt, das auf dem Tab Instanz hervorgehoben ist.
Die Ansichten Instanzen, Felder und Referenzen im Toolfenster „Heap-Dump“.

Speicherlecks finden

Wenn Sie schnell nach Klassen filtern möchten, die möglicherweise mit Speicherlecks in Verbindung stehen, öffnen Sie das Drop-down-Menü für die Klasse und wählen Sie Show activity/fragment leaks (Aktivitäts-/Fragmentlecks anzeigen) aus. Android Studio zeigt Klassen an, die seiner Meinung nach auf Speicherlecks für Activity- und Fragment-Instanzen in Ihrer App hinweisen.

Wenn Sie manueller nach Arbeitsspeicherlecks suchen möchten, sehen Sie sich die Klassen- und Instanzlisten an, um Objekte mit einer großen Retained Size (Beibehaltener Speicherplatz) zu finden. Suchen Sie nach Speicherlecks, die durch Folgendes verursacht werden:

  • Langlebige Verweise auf Activity oder Context, die den gehosteten Compose-Kompositionsgraphen (z. B. ComposeView und seine untergeordneten Composables) preisgeben können.
  • Durchsickern von Jetpack Compose-Zustandsobjekten (MutableState), Zustandshaltern oder Lambdas, die Context erfassen.
  • Vergessen, Listener oder Observer im onDispose-Block eines DisposableEffect zu bereinigen.
  • Nicht statische innere Klassen, z. B. Runnable, die eine Activity-Instanz enthalten können.
  • Caches, in denen Objekte länger als nötig gespeichert werden.

Wenn Sie potenzielle Speicherlecks finden, können Sie auf den Tabs Felder und Referenzen in Instanzdetails zur entsprechenden Instanz oder Quellcodezeile springen.

Speicherlecks zu Testzwecken auslösen

Um die Arbeitsspeichernutzung zu analysieren, sollten Sie den App-Code belasten und versuchen, Speicherlecks zu erzwingen. Eine Möglichkeit, Speicherlecks in Ihrer App zu provozieren, besteht darin, sie eine Weile laufen zu lassen, bevor Sie den Heap untersuchen. Lecks können sich bis zum Anfang der Zuweisungen im Heap ausbreiten. Je kleiner das Leck ist, desto länger müssen Sie die App ausführen, um es zu sehen.

Sie können ein Speicherleck auch auf eine der folgenden Arten auslösen:

  • Drehe das Gerät mehrmals vom Hoch- ins Querformat und wieder zurück, während es sich in verschiedenen Aktivitätsstatus befindet. Wenn das Gerät gedreht wird, kann es häufig zu einem Activity-Leck in einer App kommen (und damit auch zu einem Leck im gehosteten Compose-UI-Baum und den zugehörigen Zustandsbäumen), wenn Ihre App in asynchronen Vorgängen oder Zustandshaltern einen Verweis auf Activity oder Context enthält.
  • Wechseln Sie zwischen Ihrer App und einer anderen App, während sich die Apps in verschiedenen Aktivitätsstatus befinden. Rufen Sie beispielsweise den Startbildschirm auf und kehren Sie dann zu Ihrer App zurück.

Heap-Dump-Aufzeichnung exportieren und importieren

Sie können eine Heap-Dump-Datei auf dem Tab Past Recordings (Vergangene Aufzeichnungen) im Profiler exportieren und importieren. Android Studio speichert die Aufzeichnung als .hprof-Datei.

Wenn Sie stattdessen einen anderen .hprof-Dateianalysator wie jhat verwenden möchten, müssen Sie die .hprof-Datei vom Android-Format in das Java SE-.hprof-Dateiformat konvertieren. Verwenden Sie zum Konvertieren des Dateiformats das Tool hprof-conv im Verzeichnis {android_sdk}/platform-tools/. Führen Sie den Befehl hprof-conv mit zwei Argumenten aus: dem ursprünglichen .hprof-Dateinamen und dem Speicherort für die konvertierte .hprof-Datei, einschließlich des neuen .hprof-Dateinamens. Beispiel:

hprof-conv heap-original.hprof heap-converted.hprof

Zusätzliche Ressourcen