Profiltypen und wann sie jeweils hilfreich sind

In Android können Sie verschiedene Arten von Leistungsprofilen aufzeichnen. Wenn Sie ein Profil erstellen, können Sie Probleme im Zusammenhang mit der Ausführungsgeschwindigkeit, dem Arbeitsspeicherverbrauch und dem Stromverbrauch Ihrer App beheben.

In diesem Dokument werden die nützlichsten Profiltypen beschrieben und es wird erläutert, wann Sie welchen Typ verwenden sollten, um häufige Leistungsprobleme zu beheben.

System-Traces

Beispiel für System Tracing
Abbildung 1: Beispiel für System Tracing

Ein System-Trace ist ein leistungsstarkes Profil, das Informationen zu Prozessen, Threads, Zeitinformationen, CPU- und Aufgabenbearbeitung sowie system- oder nutzerdefinierten Ereignissen enthält.

Aus App-Sicht können die Informationen in Traces ein breites Spektrum an Bereichen abdecken, darunter Latenz, Ruckeln, Arbeitsspeicher und Akku.

System-Traces enthalten die folgenden codebasierten Ereignisse, die entweder vom System oder vom Nutzer definiert werden können. Codebasierte Ereignisse sind Ereignisse, die Nutzer über Funktionsaufrufe auslösen können.

  • Trace-Slices: stellen die Zeit zwischen verschiedenen Punkten in Ihrem Code dar. Sie können mit den APIs Trace.beginSection und Trace.endSection hinzugefügt werden.
  • Trace-Zähler: numerische Werte, die Messwerte darstellen, z. B. die Heap-Größe. Sie können mit der Trace.setCounter API hinzugefügt werden.

System-Traces enthalten auch Messwerte, die aus PerfettoSQL-Abfragen erstellt werden können und mit denen sich Analysen durchführen oder Traces vergleichen lassen.

Wir empfehlen, System-Traces für die folgenden Aufgaben zu verwenden:

  • Latenzprobleme diagnostizieren: System-Traces eignen sich hervorragend, um Latenzprobleme zu finden, die durch Verzögerungen, Wartezeiten oder Planungsprobleme verursacht werden. Andere Profiler, z. B. auf Stichproben basierende Profile, liefern nicht die Zeitinformationen, die System-Traces liefern.

  • Doppelte Berechnungen finden: Durch das Tracing lässt sich herausfinden, ob bestimmte Berechnungen wiederholt werden, was auf unnötige Vorgänge hindeuten kann.

  • Probleme mit der Sperrenkonkurrenz diagnostizieren: Anhand von Informationen zu Threadstatus und Zeitabschnitten, in denen Ressourcen blockiert sind, können Sie feststellen, ob Sperren (z. B. synchronized-Blöcke) zu Verzögerungen bei Nutzeraktionen führen.

  • Multithreading in Ihrer App nachvollziehen: In Traces werden mehrere Threads angezeigt.Für jeden Thread werden der Status und alle Trace-Abschnitte dargestellt, die vom System oder von Ihrer App hinzugefügt wurden. Anhand dieser Ansicht mit mehreren Threads können Sie nachvollziehen, welche Threads aktiv sind, welche inaktiv sind und was sie ausführen und wie sie interagieren.

  • Komplexe Leistungsanalysen durchführen: Die leistungsstarke Benutzeroberfläche und die Möglichkeit, verschiedene Arten von Informationen anzuzeigen, machen System-Traces nützlich für das Debuggen einer Vielzahl von Leistungsproblemen, einschließlich Latenz, Arbeitsspeicher und Akkunutzung.

System-Traces unterstützen auch Abfragen mit PerfettoSQL. Mit dieser leistungsstarken Funktion haben Sie folgende Möglichkeiten:

  • Bestimmte Daten extrahieren.
  • Trace-Daten in benutzerdefinierte Messwerte umwandeln
  • Sie können Debug-Tracks aus Abfragen erstellen, um die für Sie wichtigsten Dinge in der Perfetto-Benutzeroberfläche leichter zu visualisieren.
  • Komplexe Analysen direkt in der Perfetto-Benutzeroberfläche durchführen

Stack-Beispielprofile

Beispiel für ein Stackprobenprofil
Abbildung 2: Beispiel für ein Profil mit gestapelten Stichproben.

Bei Stack-Beispielprofilen werden Beispiele für die Codeausführung aufgezeichnet und die Informationen zum Aufrufstack mit einer festgelegten Rate gespeichert, während ein Thread Aufgaben auf der CPU ausführt. So können Sie nachvollziehen, was Ihr Code während der Ausführung bewirkt.

Wir empfehlen, Stapelproben für Folgendes zu verwenden:

  • Hotspots optimieren: Mithilfe von Stack-Beispielen lassen sich Teile Ihres Codes mit hoher CPU-Aktivität identifizieren. Das bedeutet, dass sich der Thread oft im Status „Wird ausgeführt“ befindet.
  • Codeausführung verstehen Mithilfe von Stack-Beispielen können Sie das allgemeine Verhalten Ihrer Codebasis nachvollziehen.
  • Code identifizieren, der nicht ausgeführt werden soll Möglicherweise finden Sie Callstacks, die überhaupt nicht ausgeführt werden sollten. Das weist auf unmittelbare Optimierungsmöglichkeiten hin.

Heap-Dumps

Beispiel für Heap-Dump
Abbildung 3: Beispiel für einen Heap-Dump.

Java-Heap-Dumps zeigen einen Snapshot des Java-Heap-Speichers Ihrer App. Dieser Snapshot enthält alle Objekte und ihre Beziehungen zueinander zum Zeitpunkt des Dumps.

Wir empfehlen, Heap-Dumps zu erfassen, um Folgendes zu tun:

  • Doppelte Objekte aufdecken: Heap-Dumps zeigen die Anzahl der Live-Objekte an, was nützlich ist, um doppelte Objekte zu verfolgen. Außerdem enthalten sie Objektverweise, mit denen Sie die Codestelle ermitteln können, an der Objekte erstellt wurden.
  • Speicherlecks finden Heap-Dumps können Arbeitsspeicher aufdecken, der zum Zeitpunkt der Erstellung des Dumps nicht mehr verwendet werden sollte, was auf potenzielle Speicherlecks hinweist.
  • Objekte identifizieren, die optimiert werden könnten Heap-Dumps zeigen Objekte, die viel Arbeitsspeicher verwenden, und ihre Anzahl. So lassen sich ineffiziente Arbeitsspeichernutzungsmuster erkennen.

Heap-Profile

Beispiel für ein Heap-Profil
Abbildung 4: Beispiel für ein Heap-Profil.

Heap-Profile sind sowohl in nativer als auch in Java-Version verfügbar und eignen sich hervorragend zum Debuggen von Speicherproblemen. Sie ähneln Callstack-Samples, aber anstatt CPU-Zyklen zu messen, werden Samples bei der Speicherzuweisung erfasst.

Wir empfehlen, Heap-Profile für Folgendes zu verwenden:

  • Speicher-Churn reduzieren Heap-Profile enthalten Stichproben mit Code-Speicherorten für Arbeitsspeicherzuweisungen. So können Sie Bereiche identifizieren, in denen viele temporäre Objekte erstellt werden, was zu häufigen Garbage Collections (GCs) in Ihrer App führen kann.
  • Speicherlecks aufdecken Heap-Profile können zusammen mit anderen Speicherprofilen verwendet werden, um Speicherlecks zu diagnostizieren und zu beheben. Sie helfen Ihnen, Speicherorte zu identifizieren, an denen deutlich mehr Speicher als erwartet zugewiesen wird.

Profile zusammenführen

Häufig analysieren Sie die Leistung mit einem einzelnen Profil. Das Erfassen mehrerer Profile oder eines einzelnen kombinierten Profils kann jedoch oft ein vollständigeres Bild liefern und bei der Diagnose komplexer Probleme helfen, die mit einem einzelnen Profil allein nicht möglich ist.

Hier einige Szenarien, in denen das Kombinieren von Profilen sinnvoll ist:

  • Szenario 1: Nicht instrumentierten Code untersuchen In einem System-Trace werden möglicherweise Latenzen für Vorgänge angezeigt, die Sie bereits instrumentiert haben. Möglicherweise benötigen Sie jedoch weitere Informationen zu nicht instrumentierten Teilen Ihres Codes, die in diesem Zeitraum ausgeführt werden. Um das Problem zu untersuchen, erstellen Sie ein Anrufstapelprofil, um den ausgeführten Code zu analysieren. Anhand dieser Informationen können Sie das Tracing verbessern, indem Sie weitere Trace-Abschnitte hinzufügen.

  • Szenario 2: Speicherlecks und automatische Speicherbereinigungen analysieren Stellen Sie sich vor, ein System-Trace zeigt einen konstanten Anstieg des Java-Heap-Speichers aufgrund von Zuweisungen, was zu häufigen automatischen Speicherbereinigungen (Garbage Collections, GCs) führt. Um die zugewiesenen Objekte zu analysieren, erstellen Sie ein Heap-Profil oder einen Heap-Dump. Dieser kombinierte Ansatz hilft Ihnen, Möglichkeiten zur Reduzierung der Arbeitsspeichernutzung zu finden. Wenn Sie beispielsweise durch Caching unnötige oder optimierbare Zuweisungen reduzieren, können Sie Garbage Collections vermeiden.