Arbeitsspeichernutzung der App mit dem Speicher-Profiler prüfen

Der Speicher-Profiler ist eine Komponente im Android Profiler. Sie hilft Ihnen beim Identifizieren von Speicherlecks und -abwanderung, die zu Ruckeln, Einfrieren und sogar App-Abstürzen führen können. Sie zeigt ein Echtzeitdiagramm der Arbeitsspeichernutzung Ihrer Anwendung und ermöglicht Ihnen, einen Heap-Dump zu erfassen, automatische Speicherbereinigungen zu erzwingen und Arbeitsspeicherzuweisungen zu verfolgen.

So öffnen Sie den Speicher-Profiler:

  1. Klicken Sie auf Ansicht > Toolfenster > Profiler. Sie können auch in der Symbolleiste auf Profil klicken.
  2. Wählen Sie in der Android Profiler-Symbolleiste das Gerät und den Anwendungsprozess aus, für den Sie ein Profil erstellen möchten. Wenn du ein Gerät über USB verbunden hast, es aber nicht in der Liste siehst, prüfe, ob das USB-Debugging aktiviert ist.
  3. Klicken Sie auf eine beliebige Stelle in der MEMORY-Zeitleiste, um den Speicher-Profiler zu öffnen.

Alternativ können Sie den Anwendungsarbeitsspeicher über die Befehlszeile mit dumpsys überprüfen und GC-Ereignisse in Logcat ansehen.

Warum Sie ein Profil für den App-Arbeitsspeicher erstellen sollten

Android stellt eine verwaltete Speicherumgebung bereit. Wenn festgestellt wird, dass Ihre App einige Objekte nicht mehr verwendet, gibt die automatische Speicherbereinigung den nicht verwendeten Arbeitsspeicher wieder an den Heap frei. Die Vorgehensweise bei Android zum Auffinden von ungenutztem Arbeitsspeicher wird ständig verbessert. Ab einem bestimmten Zeitpunkt muss das System Ihren Code jedoch auf allen Android-Versionen kurz pausieren. Meist sind die Pausen nicht wahrnehmbar. Wenn Ihre Anwendung jedoch Arbeitsspeicher schneller zuweist, als das System ihn erfassen kann, kann es zu Verzögerungen kommen, bis der Collector genügend Arbeitsspeicher freigibt, um die Zuweisungen zu erfüllen. Die Verzögerung kann dazu führen, dass Ihre App Frames überspringt und sichtbare Verzögerungen verursachen.

Auch wenn Ihre App keine langsame Geschwindigkeit aufweist, kann sie diesen Speicher bei einem Speicherleck beibehalten, auch wenn sie im Hintergrund ausgeführt wird. Dieses Verhalten kann die restliche Arbeitsspeicherleistung des Systems verlangsamen, da unnötige Ereignisse für die automatische Speicherbereinigung erzwungen werden. Schließlich wird das System gezwungen, Ihren Anwendungsprozess zu beenden, um den Arbeitsspeicher freizugeben. Wenn der Nutzer dann zu Ihrer App zurückkehrt, muss sie vollständig neu gestartet werden.

Um diese Probleme zu vermeiden, sollten Sie den Speicher-Profiler verwenden, um Folgendes zu tun:

  • Suchen Sie in der Zeitleiste nach unerwünschten Mustern bei der Speicherzuweisung, die zu Leistungsproblemen führen könnten.
  • Sie können den Java-Heap löschen, um zu sehen, welche Objekte zu einem bestimmten Zeitpunkt Arbeitsspeicher verbrauchen. Mehrere Heap-Dumps über einen längeren Zeitraum können dabei helfen, Speicherlecks zu identifizieren.
  • Erfassen Sie die Arbeitsspeicherzuweisungen während normaler und extremer Nutzerinteraktionen, um genau zu ermitteln, wo Ihr Code entweder zu viele Objekte in kurzer Zeit oder Objekte zuweist, die gehackt wurden.

Informationen zu Programmierpraktiken, die die Speichernutzung Ihrer App reduzieren können, finden Sie unter Arbeitsspeicher der App verwalten.

Speicher-Profiler – Übersicht

Wenn Sie den Speicher-Profiler zum ersten Mal öffnen, sehen Sie eine detaillierte Zeitachse zur Arbeitsspeichernutzung Ihrer App und Zugriffstools, mit denen Sie die automatische Speicherbereinigung erzwingen, einen Heap-Dump erfassen und Arbeitsspeicherzuweisungen aufzeichnen können.

Abbildung 1: Speicher-Profiler

Wie in Abbildung 1 dargestellt, umfasst die Standardansicht des Speicher-Profilers Folgendes:

  1. Eine Schaltfläche zum Erzwingen eines automatischen Speicherbereinigungsereignisses.
  2. Eine Schaltfläche zum Erfassen eines Heap-Dumps.

    Hinweis: Die Schaltfläche zum Aufzeichnen von Speicherzuweisungen wird nur dann rechts neben der Heap-Dump-Schaltfläche angezeigt, wenn das Gerät mit einem Gerät mit Android 7.1 (API-Level 25) oder niedriger verbunden ist.

  3. Ein Drop-down-Menü, mit dem Sie angeben können, wie oft der Profiler Arbeitsspeicherzuweisungen erfasst. Wenn Sie die entsprechende Option auswählen, können Sie die Anwendungsleistung während der Profilerstellung verbessern.
  4. Schaltflächen zum Heran- und Herauszoomen der Zeitleiste.
  5. Eine Schaltfläche, um zu den Live-Speicherdaten zu springen
  6. Die Ereigniszeitachse, die die Aktivitätsstatus, Nutzereingabeereignisse und Bildschirmrotationen anzeigt.
  7. Die Zeitachse der Arbeitsspeichernutzung, die Folgendes umfasst:
    • Ein gestapeltes Diagramm, das angibt, wie viel Speicher von jeder Speicherkategorie belegt wird, wie durch die y-Achse auf der linken Seite und die Farbtaste oben angegeben.
    • Eine gestrichelte Linie zeigt die Anzahl der zugewiesenen Objekte an, wie durch die y-Achse auf der rechten Seite angegeben.
    • Ein Symbol für jedes automatische Speicherbereinigungsereignis

Wenn Sie jedoch ein Gerät mit Android 7.1 oder niedriger verwenden, sind nicht alle Profildaten standardmäßig sichtbar. Wenn die Meldung „Erweiterte Profilerstellung ist für den ausgewählten Prozess nicht verfügbar“ angezeigt wird, müssen Sie die erweiterte Profilerstellung aktivieren, um Folgendes zu sehen:

  • Zeitachse des Ereignisses
  • Anzahl der zugewiesenen Objekte
  • Veranstaltungen zur automatischen Speicherbereinigung

Unter Android 8.0 und höher ist die erweiterte Profilerstellung für Anwendungen, bei denen Fehler behoben werden können, immer aktiviert.

So wird Arbeitsspeicher gezählt

Die Zahlen, die Sie oben im Speicher-Profiler sehen (Abbildung 2), basieren auf allen privaten Speicherseiten, für die Ihre App laut Android-System einen Commit durchgeführt hat. Dabei werden keine Seiten berücksichtigt, die für das System oder andere Apps freigegeben wurden.

Abbildung 2: In der Legende zur Speicheranzahl oben im Speicher-Profiler

Die Kategorien in der Arbeitsspeicheranzahl sind:

  • Java: Arbeitsspeicher von Objekten, die über Java- oder Kotlin-Code zugewiesen wurden.
  • Nativ: Arbeitsspeicher aus Objekten, die aus C- oder C++-Code zugewiesen wurden.

    Auch wenn Sie in Ihrer App kein C++ verwenden, wird hier möglicherweise nativer Arbeitsspeicher verwendet, da das Android-Framework nativen Arbeitsspeicher verwendet, um verschiedene Aufgaben in Ihrem Namen auszuführen, z. B. die Verarbeitung von Bild-Assets und anderen Grafiken, obwohl der von Ihnen geschriebene Code in Java oder Kotlin geschrieben wurde.

  • Grafiken: Arbeitsspeicher, der für Grafikzwischenspeicherwarteschlangen verwendet wird, um Pixel auf dem Bildschirm anzuzeigen, einschließlich GL-Oberflächen, GL-Texturen usw. (Beachten Sie, dass es sich um Arbeitsspeicher handelt, der von der CPU gemeinsam genutzt wird, nicht als dedizierter GPU-Arbeitsspeicher.)

  • Stack: Arbeitsspeicher, der sowohl von nativen als auch von Java-Stacks in Ihrer Anwendung verwendet wird. Dies hängt in der Regel davon ab, wie viele Threads in Ihrer Anwendung ausgeführt werden.

  • Code: Arbeitsspeicher, den Ihre Anwendung für Code und Ressourcen verwendet, z. B. DEX-Bytecode, optimierter oder kompilierter DEX-Code, SO-Bibliotheken und Schriftarten.

  • Sonstiges: Von der Anwendung verwendeter Arbeitsspeicher, der vom System kategorisiert werden kann.

  • Zugewiesen: Die Anzahl der von Ihrer App zugewiesenen Java-/Kotlin-Objekte. In C oder C++ zugewiesene Objekte werden nicht berücksichtigt.

    Wenn das Gerät mit einem Gerät mit Android 7.1 und niedriger verbunden ist, beginnt die Anzahl der Zuweisungen erst ab dem Zeitpunkt, zu dem der Speicher-Profiler mit Ihrer laufenden Anwendung verbunden ist. Objekte, die vor dem Start der Profilerstellung zugewiesen wurden, werden also nicht berücksichtigt. Android 8.0 und höher enthält jedoch ein Profilerstellungstool auf dem Gerät, mit dem alle Zuweisungen erfasst werden. Diese Zahl steht also immer für die Gesamtzahl der ausstehenden Java-Objekte in Ihrer App unter Android 8.0 und höher.

Im Vergleich zur Arbeitsspeicheranzahl des vorherigen Android Monitor-Tools zeichnet der neue Speicher-Profiler den Arbeitsspeicher anders auf, sodass es den Anschein erweckt, dass die Arbeitsspeichernutzung jetzt höher ist. Der Speicher-Profiler überwacht einige zusätzliche Kategorien, die die Gesamtsumme erhöhen. Wenn Ihnen jedoch nur der Java-Heap-Arbeitsspeicher wichtig ist, sollte die "Java"-Zahl dem Wert aus dem vorherigen Tool entsprechen. Auch wenn die Java-Nummer wahrscheinlich nicht genau mit derjenigen übereinstimmt, die Sie in Android Monitor angezeigt haben, berücksichtigt die neue Anzahl alle Seiten des physischen Arbeitsspeichers, die dem Java-Heap Ihrer Anwendung zugewiesen wurden, seit diese von Zygote abgespalten wurde. Damit erhalten Sie eine genaue Darstellung davon, wie viel physischer Speicher Ihre Anwendung tatsächlich verwendet.

Arbeitsspeicherzuweisungen ansehen

Die Arbeitsspeicherzuweisungen zeigen, wie die einzelnen Java-Objekte und die JNI-Referenz in Ihrem Arbeitsspeicher zugewiesen wurden. Der Speicher-Profiler zeigt Ihnen insbesondere Folgendes zu Objektzuweisungen:

  • Welche Arten von Objekten zugewiesen wurden und wie viel Platz diese genutzt haben.
  • Der Stacktrace jeder Zuweisung, einschließlich des Threads.
  • Wenn die Zuweisung der Objekte aufgehoben wurde (nur bei Verwendung eines Geräts mit Android 8.0 oder höher).

Wählen Sie Java / Kotlin-Zuweisungen aufzeichnen und dann Datensatz aus, um Java- und Kotlin-Zuweisungen aufzuzeichnen. Wenn auf dem Gerät Android 8 oder höher ausgeführt wird, wechselt die Speicher-Profiler-Benutzeroberfläche zu einem separaten Bildschirm, auf dem die laufende Aufzeichnung angezeigt wird. Sie können mit der Minizeitachse über der Aufnahme interagieren, z. B. um den Auswahlbereich zu ändern. Wählen Sie zum Abschließen der Aufzeichnung Beenden aus.

Visualisierung von Java-Zuweisungen in Memory Profiler

Unter Android 7.1 und niedriger verwendet der Speicher-Profiler die Legacy-Zuordnungsaufzeichnung, die die Aufzeichnung auf der Zeitachse anzeigt, bis Sie auf Beenden klicken.

Nachdem Sie eine Region auf der Zeitachse ausgewählt oder eine Aufzeichnungssitzung mit einem Gerät mit Android 7.1 oder niedriger beendet haben, wird die Liste der zugewiesenen Objekte angezeigt, gruppiert nach Klassennamen und sortiert nach Heap-Anzahl.

So prüfen Sie den Zuweisungseintrag:

  1. Suchen Sie in der Liste nach Objekten, die eine ungewöhnlich hohe Heap-Anzahl haben und möglicherweise gehackt werden. Wenn Sie nach bekannten Klassen suchen möchten, können Sie sie alphabetisch sortieren, indem Sie auf die Spaltenüberschrift Class Name (Klassenname) klicken. Klicken Sie dann auf einen Kursnamen. Rechts wird der Bereich Instanzansicht eingeblendet. Hier sehen Sie jede Instanz dieser Klasse (siehe Abbildung 3).
    • Alternativ können Sie Objekte schnell finden, indem Sie auf Filter klicken oder Strg + F (Befehlstaste + F auf einem Mac) drücken und einen Klassen- oder Paketnamen in das Suchfeld eingeben. Sie können auch nach Methodennamen suchen, wenn Sie im Drop-down-Menü die Option Nach Aufrufstack anordnen auswählen. Wenn Sie reguläre Ausdrücke verwenden möchten, klicken Sie das Kästchen neben Regex an. Klicken Sie auf das Kästchen neben Groß-/Kleinschreibung beachten, wenn bei der Suchanfrage zwischen Groß- und Kleinschreibung unterschieden wird.
  2. Klicken Sie im Bereich Instanzansicht auf eine Instanz. Unten wird der Tab Aufrufstapel angezeigt. Hier sehen Sie, wo und in welchem Thread die Instanz zugewiesen wurde.
  3. Klicken Sie auf dem Tab Aufrufstack mit der rechten Maustaste auf eine Zeile und wählen Sie Weiter zum Quellcode aus, um den Code im Editor zu öffnen.

Abbildung 3: Details zu jedem zugewiesenen Objekt werden rechts in der Instanzansicht angezeigt.

Mit den beiden Menüs über der Liste der zugewiesenen Objekte können Sie auswählen, welcher Heap überprüft und wie die Daten organisiert werden sollen.

Wählen Sie im Menü links aus, welcher Heap überprüft werden soll:

  • Standardheap: Wenn vom System kein Heap angegeben wurde.
  • image Heap: Das Systemstart-Image, das Klassen enthält, die während des Bootvorgangs vorab geladen werden. Zuweisungen werden hier garantiert nie verschoben oder entfernt.
  • Zygote-Heap: Der Copy-on-Write-Heap, in dem ein Anwendungsprozess im Android-System abgespalten wird.
  • App-Heap: Der primäre Heap, auf dem die App Arbeitsspeicher zuweist.
  • JNI-Heap: Der Heap, der zeigt, wo JNI-Referenzen (Java Native Interface) zugewiesen und freigegeben werden.

Wählen Sie im Menü rechts aus, wie die Zuweisungen angeordnet werden sollen:

  • Nach Kurs anordnen: Gruppiert alle Zuweisungen nach Kursnamen. Das ist die Standardeinstellung.
  • Nach Paket anordnen: Gruppiert alle Zuweisungen basierend auf dem Paketnamen.
  • Nach Aufrufstack anordnen: Gruppiert alle Zuweisungen in den entsprechenden Aufrufstack.

Anwendungsleistung während der Profilerstellung verbessern

Zur Verbesserung der Anwendungsleistung während der Profilerstellung führt der Arbeitsspeicher-Profiler standardmäßig regelmäßig Stichproben der Arbeitsspeicherzuweisungen. Beim Testen auf Geräten mit API-Ebene 26 oder höher können Sie dieses Verhalten über das Drop-down-Menü Zuordnungsverfolgung ändern. Folgende Optionen sind verfügbar:

  • Full: Erfasst alle Objektzuweisungen im Arbeitsspeicher. Dies ist das Standardverhalten in Android Studio 3.2 und früheren Versionen. Wenn Sie eine Anwendung haben, die viele Objekte zuweist, kann es bei der Profilerstellung zu sichtbaren Verlangsamungen der Anwendung kommen.
  • Stichproben: Es werden in regelmäßigen Intervallen Stichproben der Objektzuweisungen im Speicher erhoben. Dies ist die Standardoption und hat weniger Auswirkungen auf die Anwendungsleistung während der Profilerstellung. Anwendungen, die viele Objekte über einen kurzen Zeitraum zuweisen, können weiterhin deutliche Verlangsamungen aufweisen.
  • Aus: Die Arbeitsspeicherzuweisung Ihrer App wird nicht mehr verfolgt.

Globale JNI-Referenzen ansehen

Java Native Interface (JNI) ist ein Framework, das es Java-Code und nativem Code ermöglicht, sich gegenseitig aufzurufen.

JNI-Referenzen werden manuell vom nativen Code verwaltet. Daher können Java-Objekte, die von nativem Code verwendet werden, zu lange aktiv gehalten werden. Einige Objekte auf dem Java-Heap sind möglicherweise nicht mehr erreichbar, wenn eine JNI-Referenz verworfen wird, ohne zuvor explizit gelöscht zu werden. Es ist auch möglich, dass das globale JNI-Referenzlimit erreicht ist.

Zum Beheben solcher Probleme können Sie die Ansicht JNI-Heap im Speicher-Profiler verwenden, um alle globalen JNI-Referenzen zu durchsuchen und nach Java-Typen und nativen Aufrufstacks zu filtern. Mit diesen Informationen können Sie feststellen, wann und wo globale JNI-Referenzen erstellt und gelöscht werden.

Wählen Sie, während Ihre Anwendung ausgeführt wird, einen Teil der Zeitachse aus, den Sie prüfen möchten, und wählen Sie im Drop-down-Menü über der Klassenliste JNI-Heap aus. Sie können dann wie gewohnt Objekte im Heap untersuchen und auf dem Tab Allocation Call Stack (Zuordnungsaufruf-Stack) doppelt auf Objekte klicken, um zu sehen, wo die JNI-Referenzen in Ihrem Code zugewiesen und in Ihrem Code freigegeben werden (siehe Abbildung 4).

Abbildung 4: Globale JNI-Referenzen ansehen

Wenn Sie die Arbeitsspeicherzuweisungen für den JNI-Code Ihrer App prüfen möchten, müssen Sie die App auf einem Gerät mit Android 8.0 oder höher bereitstellen.

Weitere Informationen zu JNI finden Sie in den JNI-Tipps.

Nativer Speicher-Profiler

Der Speicher-Profiler von Android Studio enthält einen nativen Speicher-Profiler für Apps, die auf physischen und virtuellen Geräten mit Android 10 und höher bereitgestellt werden.

Der native Speicher-Profiler verfolgt Zuweisungen/Deals von Objekten im nativen Code für einen bestimmten Zeitraum und stellt folgende Informationen bereit:

  • Zuweisungen:Die Anzahl der Objekte, die während des ausgewählten Zeitraums über malloc() oder den Operator new zugewiesen wurden.
  • Deallocations:Die Anzahl der Objekte, die im ausgewählten Zeitraum über free() oder den Operator delete aufgehoben wurden.
  • Allocations size (Größe der Zuweisungen): Die aggregierte Größe in Byte aller Zuweisungen im ausgewählten Zeitraum.
  • Deallocations-Größe:Die aggregierte Größe in Byte des gesamten freigegebenen Arbeitsspeichers im ausgewählten Zeitraum.
  • Gesamtzahl:Der Wert in der Spalte Allocations minus der Wert in der Spalte Deallocations
  • Verbleibende Größe:Der Wert in der Spalte Allocations-Größe abzüglich des Werts in der Spalte Größe des Deals.

Nativer Speicher-Profiler

Wenn Sie native Zuweisungen auf Geräten mit Android 10 und höher aufzeichnen möchten, wählen Sie Native Zuweisungen aufzeichnen und dann Datensatz aus. Die Aufzeichnung wird fortgesetzt, bis Sie auf Beenden klicken. Danach wechselt die Memory Profiler-Benutzeroberfläche zu einem separaten Bildschirm, auf dem die native Aufzeichnung angezeigt wird.

Schaltfläche „Native Zuweisungen aufzeichnen“

Unter Android 9 und niedriger ist die Option Native Zuweisungen aufzeichnen nicht verfügbar.

Standardmäßig verwendet der native Speicher-Profiler eine Stichprobengröße von 32 Byte: Jedes Mal, wenn 32 Byte Arbeitsspeicher zugewiesen werden, wird ein Arbeitsspeicher-Snapshot erstellt. Eine kleinere Stichprobengröße führt zu häufigeren Snapshots und somit zu genaueren Daten zur Arbeitsspeichernutzung. Eine größere Stichprobengröße führt zu weniger genauen Daten, verbraucht jedoch weniger Ressourcen im System und verbessert die Leistung während der Aufzeichnung.

So ändern Sie die Stichprobengröße des nativen Speicher-Profilers:

  1. Wählen Sie Run > Edit Configurations (Ausführen > Konfigurationen bearbeiten) aus.
  2. Wählen Sie im linken Bereich Ihr App-Modul aus.
  3. Klicken Sie auf den Tab Profilerstellung und geben Sie die Stichprobengröße in das Feld Intervall der Stichprobenerhebung für nativer Arbeitsspeicher (Byte) ein.
  4. Erstellen Sie Ihre Anwendung noch einmal und führen Sie sie aus.

Heap-Dump erfassen

Ein Heap-Dump zeigt, welche Objekte in Ihrer Anwendung zum Zeitpunkt der Erfassung des Heap-Dumps Arbeitsspeicher verwenden. Besonders nach einer längeren Nutzersitzung kann ein Heap-Dump dabei helfen, Speicherlecks zu identifizieren, da Objekte angezeigt werden, die sich noch im Arbeitsspeicher befinden und von denen Sie annehmen, dass sie nicht mehr vorhanden sein sollten.

Nachdem Sie einen Heap-Dump erfasst haben, können Sie Folgendes aufrufen:

  • Welche Objekttypen Ihre App zugewiesen hat und wie viele von jedem Objekt.
  • Wie viel Arbeitsspeicher die einzelnen Objekte verbrauchen.
  • Wo Verweise auf die einzelnen Objekte in Ihrem Code enthalten sind.
  • Der Aufrufstack, wo ein Objekt zugewiesen wurde. Aufrufstacks sind derzeit mit einem Heap-Dump nur unter Android 7.1 und niedriger verfügbar, wenn Sie den Heap-Dump bei der Aufzeichnung von Zuweisungen erfassen.

Wenn Sie einen Heap-Dump erfassen möchten, klicken Sie auf Heap-Dump erfassen und wählen Sie Aufzeichnen aus. Beim Speichern des Heaps kann sich der Umfang des Java-Arbeitsspeichers vorübergehend erhöhen. Das ist normal, da der Heap-Dump im selben Prozess wie Ihre Anwendung ausgeführt wird und etwas Arbeitsspeicher benötigt, um die Daten zu erfassen.

Nachdem der Profiler die Erfassung des Heap-Dumps abgeschlossen hat, wechselt die Benutzeroberfläche des Speicher-Profilers zu einem separaten Bildschirm mit dem Heap-Dump.

Abbildung 5: Sie sehen den Heap-Dump.

Wenn Sie genauer wissen möchten, wann der Dump erstellt wird, können Sie am kritischen Punkt im App-Code einen Heap-Dump erstellen. Rufen Sie dazu dumpHprofData() auf.

In der Liste der Kurse sehen Sie die folgenden Informationen:

  • Zuweisungen: Anzahl der Zuweisungen im Heap.
  • Native Größe: Gesamtmenge des von diesem Objekttyp verwendeten nativen Arbeitsspeichers in Byte. Diese Spalte ist nur für Android 7.0 und höher sichtbar.

    Hier sehen Sie Arbeitsspeicher für einige in Java zugewiesene Objekte, weil Android für einige Framework-Klassen wie Bitmap nativen Arbeitsspeicher verwendet.

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

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

Mit den beiden Menüs über der Liste der zugewiesenen Objekte können Sie auswählen, welche Heap-Dumps überprüft werden sollen und wie die Daten organisiert werden sollen.

Wählen Sie im Menü links aus, welcher Heap überprüft werden soll:

  • Standardheap: Wenn vom System kein Heap angegeben wurde.
  • App-Heap: Der primäre Heap, auf dem die App Arbeitsspeicher zuweist.
  • image Heap: Das Systemstart-Image, das Klassen enthält, die während des Bootvorgangs vorab geladen werden. Zuweisungen werden hier garantiert nie verschoben oder entfernt.
  • Zygote-Heap: Der Copy-on-Write-Heap, in dem ein Anwendungsprozess im Android-System abgespalten wird.

Wählen Sie im Menü rechts aus, wie die Zuweisungen angeordnet werden sollen:

  • Nach Kurs anordnen: Gruppiert alle Zuweisungen nach Kursnamen. Das ist die Standardeinstellung.
  • Nach Paket anordnen: Gruppiert alle Zuweisungen basierend auf dem Paketnamen.
  • Nach Aufrufstack anordnen: Gruppiert alle Zuweisungen in den entsprechenden Aufrufstack. Diese Option funktioniert nur, wenn Sie den Heap-Dump beim Aufzeichnen von Zuweisungen erfassen. Dennoch befinden sich im Heap wahrscheinlich Objekte, die vor Beginn der Aufzeichnung zugewiesen wurden. Diese Zuweisungen werden also zuerst angezeigt und einfach nach Klassennamen aufgelistet.

Die Liste wird standardmäßig nach der Spalte Beibehaltene Größe sortiert. Um nach den Werten in einer anderen Spalte zu sortieren, klicken Sie auf die Spaltenüberschrift.

Klicken Sie auf einen Klassennamen, um das Fenster Instanzansicht rechts zu öffnen (siehe Abbildung 6). Jede aufgelistete Instanz enthält Folgendes:

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

Abbildung 6: Die für die Erfassung eines Heap-Dumps erforderliche Dauer ist in der Zeitachse angegeben.

So prüfen Sie Ihren Heap:

  1. Suchen Sie in der Liste nach Objekten, die eine ungewöhnlich hohe Heap-Anzahl haben und möglicherweise gehackt werden. Wenn Sie nach bekannten Klassen suchen möchten, können Sie sie alphabetisch sortieren, indem Sie auf die Spaltenüberschrift Class Name (Klassenname) klicken. Klicken Sie dann auf einen Kursnamen. Rechts wird der Bereich Instanzansicht eingeblendet. Hier sehen Sie jede Instanz dieser Klasse (siehe Abbildung 6).
    • Alternativ können Sie Objekte schnell finden, indem Sie auf Filter klicken oder Strg + F (Befehlstaste + F auf einem Mac) drücken und einen Klassen- oder Paketnamen in das Suchfeld eingeben. Sie können auch nach Methodennamen suchen, wenn Sie im Drop-down-Menü die Option Nach Aufrufstack anordnen auswählen. Wenn Sie reguläre Ausdrücke verwenden möchten, klicken Sie das Kästchen neben Regex an. Klicken Sie auf das Kästchen neben Groß-/Kleinschreibung beachten, wenn bei der Suchanfrage zwischen Groß- und Kleinschreibung unterschieden wird.
  2. Klicken Sie im Bereich Instanzansicht auf eine Instanz. Unten wird der Tab Referenzen geöffnet. Er enthält alle Verweise auf dieses Objekt.

    Alternativ können Sie auf den Pfeil neben dem Instanznamen klicken, um alle zugehörigen Felder aufzurufen, und dann auf einen Feldnamen klicken, um alle zugehörigen Verweise anzusehen. Wenn Sie die Instanzdetails für ein Feld ansehen möchten, klicken Sie mit der rechten Maustaste auf das Feld und wählen Sie Zur Instanz aus.

  3. Wenn Sie auf dem Tab Referenzen eine Referenz identifizieren, die Speicherlecks verursacht, klicken Sie mit der rechten Maustaste darauf und wählen Sie Zur Instanz aus. Dadurch wird die entsprechende Instanz aus dem Heap-Dump ausgewählt und ihre eigenen Instanzdaten angezeigt.

Suchen Sie im Heap-Dump nach Speicherlecks, die die folgenden Ursachen haben:

  • Langlebige Verweise auf Activity, Context, View, Drawable und andere Objekte, die einen Verweis auf den Container Activity oder Context enthalten können.
  • Nicht statische innere Klassen wie ein Runnable, die eine Activity-Instanz enthalten können.
  • Caches, die Objekte länger als nötig enthalten

Heap-Dump als HPROF-Datei speichern

Nachdem Sie einen Heap-Dump erfasst haben, werden die Daten im Speicher-Profiler nur angezeigt, wenn der Profiler ausgeführt wird. Wenn Sie die Profilerstellungssitzung beenden, geht der Heap-Dump verloren. Wenn Sie ihn also zur späteren Überprüfung speichern möchten, exportieren Sie den Heap-Dump in eine HPROF-Datei. In Android Studio 3.1 und niedriger befindet sich die Schaltfläche Aufnahme in Datei exportieren auf der linken Seite der Symbolleiste unterhalb der Zeitachse. In Android Studio 3.2 und höher befindet sich im Bereich Sitzungen rechts neben jedem Heap-Dump die Schaltfläche Heap-Dump exportieren. Speichern Sie die Datei im Dialogfeld Exportieren als mit der Dateiendung .hprof.

Wenn Sie ein anderes HPROF-Analysetool wie jhat verwenden möchten, müssen Sie die HPROF-Datei vom Android-Format in das Java SE HPROF-Format konvertieren. Dazu können Sie das hprof-conv-Tool verwenden, das im Verzeichnis android_sdk/platform-tools/ enthalten ist. Führen Sie den Befehl hprof-conv mit zwei Argumenten aus: der ursprünglichen HPROF-Datei und dem Speicherort, an dem die konvertierte HPROF-Datei geschrieben werden soll. Beispiele:

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

Heap-Dumpdatei importieren

Klicken Sie zum Importieren einer HPROF-Datei (.hprof) im Bereich Sitzungen auf Neue Profilerstellungssitzung starten . Wählen Sie dann Aus Datei laden und dann die Datei aus dem Dateibrowser aus.

Sie können eine HPROF-Datei auch importieren, indem Sie sie aus dem Dateibrowser in ein Editorfenster ziehen.

Speicherleck-Erkennung im Speicher-Profiler

Beim Analysieren eines Heap-Dumps im Speicher-Profiler können Sie Profildaten filtern, die Android Studio auf Speicherlecks für Activity- und Fragment-Instanzen in Ihrer App hinweisen könnte.

Der Filter zeigt folgende Datentypen an:

  • Activity Instanzen, die gelöscht wurden, aber noch referenziert werden.
  • Fragment-Instanzen, die keinen gültigen FragmentManager haben, aber noch referenziert werden.

In bestimmten Situationen wie den folgenden kann der Filter falsch-positive Ergebnisse liefern:

  • Ein Fragment wurde erstellt, aber noch nicht verwendet.
  • Ein Fragment wird im Cache gespeichert, aber nicht als Teil einer FragmentTransaction.

Wenn Sie diese Funktion verwenden möchten, müssen Sie zuerst einen Heap-Dump erfassen oder eine Heap-Dump-Datei in Android Studio importieren. Um die Fragmente und Aktivitäten anzuzeigen, die möglicherweise Speicherlecks verursachen, klicken Sie im Heap-Dump-Bereich des Speicher-Profilers das Kästchen Activity/Fragment Leaks (Aktivitäts-/Fragment-Leaks) an (siehe Abbildung 7).

Profiler: Erkennung von Speicherlecks

Abbildung 7: Heap-Dump nach Speicherlecks filtern

Techniken zum Erstellen eines Arbeitsspeicherprofils

Bei der Verwendung des Speicher-Profilers sollten Sie Ihren Anwendungscode belasten und versuchen, Speicherlecks zu erzwingen. Eine Möglichkeit, Speicherlecks in Ihrer App zu verursachen, besteht darin, sie eine Weile laufen zu lassen, bevor Sie den Heap untersuchen. Lecks können bis an die Spitze der Zuweisungen im Heap gelangen. Je kleiner das Speicherleck 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:

  • Drehen Sie das Gerät in unterschiedlichen Aktivitätszuständen mehrmals vom Hoch- ins Querformat und wieder zurück. Das Drehen des Geräts kann häufig dazu führen, dass in einer App ein Activity-, Context- oder View-Objekt verloren geht, da das Activity-Objekt neu erstellt wird. Wenn Ihre App einen Verweis auf eines dieser Objekte an anderer Stelle hat, kann das System diesen nicht automatisch bereinigen.
  • Zwischen Ihrer App und einer anderen App wechseln, wenn sie verschiedene Aktivitätsstatus haben. Rufen Sie dazu den Startbildschirm auf und kehren Sie dann zu Ihrer App zurück.

Tipp:Sie können die oben genannten Schritte auch mit dem Test-Framework monkeyrunner ausführen.