Um den Speicherbedarf Ihres Spiels effektiv zu optimieren, müssen Sie zuerst wissen, wie Arbeitsspeicher auf der Android-Plattform gemessen wird und wie Sie Systemtelemetrie, Diagnose-APIs und Profiling-Tools verwenden. In diesem Leitfaden wird beschrieben, wie Sie die Arbeitsspeicherzuweisungen Ihres Spiels gemäß den neuen Plattformrichtlinien überwachen, erfassen und analysieren.
RSS- und Auslagerungsmesswerte
Um das Arbeitsspeicherverhalten Ihres Spiels effektiv zu analysieren und zu debuggen, müssen Sie die genauen technischen Messwerte kennen, die die Android-Plattform für die Arbeitsspeicherverwaltung verwendet. Ausführliche Hintergrundinformationen zur Verarbeitung und Überwachung dieses Telemetrieparameters in der Praxis finden Sie in der Dokumentation zu Android Vitals – Arbeitsspeichernutzung (anonymer RSS + Auslagerung).
1. Anonymer RSS (RssAnon)
Die Resident Set Size (RSS) misst den Teil des Arbeitsspeichers, der von einem Prozess belegt wird und sich im physischen RAM des Geräts befindet. RSS wird in dateigestützten und anonymen Arbeitsspeicher unterteilt. Der Messwert für die Android-Verwaltung konzentriert sich ausschließlich auf den anonymen RSS:
- Inhalt: Arbeitsspeicherseiten, die direkt von Ihrem Spielprozess zugewiesen werden und nicht mit einer physischen Datei im Speicher verknüpft sind. Zu diesen Seiten gehören Java- oder Kotlin-Heaps, Thread-Ausführungsstacks und vor allem native Arbeitsspeicherzuweisungen (z. B. benutzerdefinierte C++-Engine-Zuweisungen oder Arbeitsspeicherblöcke, die mit nativem „malloc“ oder „new“ angefordert und von der Spiellogik geändert wurden). Weitere Informationen zu diesem Messwert finden Sie im Wörterbuch für den Prozessarbeitsspeicher (RSS).
- Bedeutung: Spiel-Engines verwenden massive native Arbeitsspeicherpools für Physik, Rendering und Logik. Da diese Pools nicht durch Dateien gesichert sind, befinden sie sich vollständig im anonymen RSS und machen den Großteil des physischen Arbeitsspeicherbedarfs Ihres Spiels aus.
2. Nicht komprimierte Auslagerung (VmSwap)
Android unterstützt aufgrund von Verschleiß und Latenzbeschränkungen des Flash-Speichers keinen herkömmlichen festplattenbasierten Auslagerungsspeicher. Stattdessen wird zRAM (nicht komprimierte Auslagerung) verwendet:
- Inhalt: Wenn der Druck auf den physischen RAM steigt, komprimiert der Arbeitsspeicherverwaltungs-Daemon des Kernels inaktive anonyme Seiten und verschiebt sie in einen dedizierten, nicht komprimierten Teil des physischen RAM (zRAM).
- Berechnung des Messwerts: Das System verfolgt dies anhand der nicht komprimierten Größe (VmSwap), um den tatsächlichen physischen Arbeitsspeicherbedarf des Spiels zu ermitteln. Wenn Ihr Spiel Arbeitsspeicher zuweist und das System ihn in zRAM auslagert, wird er trotzdem auf den gesamten Arbeitsspeicherbedarf Ihres Spiels angerechnet.
3. Prozessstatus
Die Arbeitsspeichernutzung wird in Android Vitals nach Prozessstatus aufgeschlüsselt. Für Spieleentwickler können auch Drittanbieter-SDKs oder Spiele unerwartet vom Nutzer wahrgenommene Dienste oder Hintergrunddienste auslösen.
- Inhalt: Vordergrund, wahrnehmbare Dienste, Hintergrund und Cache.
- Bedeutung: Verschiedene Prozessstatus haben unterschiedliche Auswirkungen auf die
Arbeitsspeicherverwaltung des Android-Betriebssystems. Sie wissen möglicherweise nicht, dass Ihr Spiel mit einem sensiblen Prozessstatus ausgeführt wird, wenn eines der Drittanbieter-SDKs versehentlich eine Hintergrundaufgabe auslöst. Mit
RunningAppProcessInfokönnen Sie prüfen, ob Ihr Spiel im Hintergrund ausgeführt wird.
Application Programming Interfaces (APIs)
Android bietet System-APIs, mit denen Ihr Spiel dynamisch auf Arbeitsspeicherdruck reagieren und detaillierte Arbeitsspeicherdiagnosen zur Laufzeit erfassen kann.
Auf Arbeitsspeicher-Trim-Ereignisse reagieren
Das System verwendet onTrimMemory, um Ihre App über Lebenszyklusereignisse zu benachrichtigen, die
eine gute Gelegenheit für Ihre App darstellen, die Arbeitsspeichernutzung freiwillig zu reduzieren
und zu vermeiden, dass sie vom Low-Memory-Killer (LMK) beendet wird, um Arbeitsspeicher für
andere Apps freizugeben.
Wenn das System Ihre App im Hintergrund beendet, dauert der langsame Kaltstart beim Fortsetzen länger. Durch Reduzieren der Arbeitsspeichernutzung im Hintergrund können diese Beendigungen im Hintergrund verhindert werden.
Geben Sie bei der Reaktion auf Trim-Ereignisse große, rekonstruierbare Arbeitsspeicherzuweisungen frei, die nicht sofort benötigt werden:
Beispiel: Cachen Sie Bitmaps, die aus dem lokalen Speicher decodiert wurden, oder löschen Sie sie als Reaktion auf
TRIM_MEMORY_UI_HIDDEN.
Kotlin
class MainActivity : AppCompatActivity(), ComponentCallbacks2 {
override fun onTrimMemory(level: Int) {
if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// Release memory related to UI elements, such as bitmap caches.
}
if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
// Release memory related to background processing, such as by
// closing a database connection.
}
}
}
Java
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
public void onTrimMemory(int level) {
switch (level) {
if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// Release memory related to UI elements, such as bitmap caches.
}
if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
// Release memory related to background processing, such as by
// closing a database connection.
}
}
}
}
ProfilingManager
Die ProfilingManager API wurde in Android 15 (API-Level 35) eingeführt und ermöglicht es
Anwendungen, programmgesteuert definierte Snapshots (z. B. Heap
Profile, System-Traces und Java-Heap-Dumps) direkt zur Laufzeit zu erfassen.
Entwickler können Erfassungen manuell in bestimmten Szenen auslösen oder automatische Auslöser wie TRIGGER_TYPE_ANOMALY registrieren, um automatisch eine Erfassung auszulösen, wenn der Spielprozess die Grenzwerte des Arbeitsspeicherbegrenzers überschreitet. Spieleentwickler müssen jedoch kritische Einschränkungen in modernen Spiel-Engines berücksichtigen:
Hinweis:Moderne Spiel-Engines (z. B. Unity oder Unreal) verwalten die Ausführungsleistung, indem sie mit „mmap“ und dem Flag „MAP_ANONYMOUS“ massive virtuelle Arbeitsspeicherblöcke vom Kernel vorab zuweisen. Die Engines verwenden dann benutzerdefinierte Unterzuweiser (z. B. den nativen Arbeitsspeicher-Manager von Unity oder die BinnedAllocators von Unreal), um Arbeitsspeicherblöcke intern zu unterteilen und zuzuweisen.
ApplicationExitInfo
Wenn Ihr Spiel im Hintergrund beendet oder beendet wird, weil es die individuellen Arbeitsspeicherlimits für Prozesse überschritten hat, wird das Ereignis nicht von Standardmechanismen für Java- oder native Crash-Dumps (z. B. Firebase Crashlytics) registriert. Um diese
Beendigungen programmgesteuert abzufragen und zu protokollieren, sollten Entwickler beim Start des Spiels die
ApplicationExitInfo API verwenden.
- Implementierung: Rufen Sie beim Start
ActivityManager.getHistoricalProcessExitReasons()auf, um die Beendigungsgründe der letzten Sitzungen abzurufen. - Wichtige Gründe für die Beendigung aufgrund von Arbeitsspeicherproblemen:
REASON_LOW_MEMORY: Gibt an, dass der Prozess vom Low-Memory-Killer (LMK) des Systems beendet wurde. Diese Beendigung tritt auf, wenn der Arbeitsspeicherdruck auf dem Gerät hoch ist und das Betriebssystem RAM freigeben muss. Dieser Beendigungsgrund gibt an, dass der Arbeitsspeicherbedarf Ihres Spiels im Hintergrund zu groß ist, um mit anderen Anwendungen zu koexistieren.REASON_MEMORY_LIMITER(Android 17 (API-Level 37) und höher): Gibt an, dass der Prozess speziell beendet wurde, weil er das vom Arbeitsspeicherbegrenzer der Plattform zugewiesene Arbeitsspeicherlimit der Cgroup (RssAnon + VmSwap) überschritten hat. Diese Beendigung kann auch auftreten, wenn auf dem Gerät noch ausreichend physischer Arbeitsspeicher vorhanden ist, was eine direkte Verletzung der individuellen Prozesslimits bedeutet.
Verfügbare Tools verwenden
Verwenden Sie die folgenden Plattformtools während der Entwicklung und Qualitätssicherung, um die Arbeitsspeichernutzung Ihres Spiels genau zu messen.
meminfo
Dieses Tool erfasst Arbeitsspeicherstatistiken, um zu zeigen, wie viel PSS-Arbeitsspeicher zugewiesen wurde und für welche Kategorien er verwendet wurde.
Geben Sie die meminfo-Statistiken auf eine der folgenden Arten aus:
- Verwenden Sie den Befehl
adb shell dumpsys meminfo package-name. - Verwenden Sie den
MemoryInfoAufruf aus der Android Debug API.
Die PrivateDirty Statistik zeigt die Menge an RAM im Prozess
die nicht auf die Festplatte ausgelagert werden kann und nicht mit anderen Prozessen geteilt wird. Der Großteil dieser Menge wird dem System zur Verfügung gestellt, wenn dieser Prozess beendet wird.
Arbeitsspeicher-Tracepoints
Arbeitsspeicher-Tracepoints verfolgen die Menge an RSS-Arbeitsspeicher, die von Ihrem Spiel verwendet wird. Die Berechnung der RSS-Arbeitsspeichernutzung ist viel schneller als die Berechnung der PSS-Nutzung. Da die Berechnung schneller ist, zeigt RSS eine feinere Granularität bei Änderungen der Arbeitsspeichergröße, um die maximale Arbeitsspeichernutzung genauer zu messen. Daher ist es einfacher, Spitzen zu erkennen, die dazu führen könnten, dass das Spiel Out of Memory ist.
Perfetto
Perfetto ist eine Reihe von Tools zum Erfassen von Leistungs- und Arbeitsspeicher
informationen auf einem Gerät und zum Anzeigen dieser Informationen in einer webbasierten Benutzeroberfläche. Es unterstützt beliebig lange Traces, sodass Sie sehen können, wie sich der RSS im Laufe der Zeit ändert. Sie können auch SQL-Abfragen für die erzeugten Daten zur Offlineverarbeitung ausführen. Aktivieren Sie lange
Traces in der System-Tracing-App. Achten Sie darauf, dass die memory:Memory Kategorie
für den Trace aktiviert ist. Für benutzerdefinierte Arbeitsspeicherinstrumentierung in der Entwicklung und
beim Testen können Sie auch die (Beta-) heapprofd API verwenden.
RssAnon und Auslagerung in Perfetto prüfen
Wenn Sie die Auswirkungen des anonymen Arbeitsspeichers und der zRAM-Auslagerung Ihres Spiels prüfen möchten, laden Sie die Trace-Datei in der webbasierten Benutzeroberfläche unter ui.perfetto.dev und folgen Sie diesen analytischen Techniken, die für detaillierte Arbeitsspeicher-Fallstudien entwickelt wurden (weitere Informationen finden Sie unter Perfetto Memory Analysis Case Studies):
1. Arbeitsspeicherzähler auf der Zeitachse visualisieren
- Prozess suchen: Suchen Sie in der Navigationsliste nach dem Paketnamen oder Prozessnamen Ihres Spiels.
- Trackgruppe maximieren: Klicken Sie auf die Zeile Ihres Prozesses, um die Thread-Tracks zu maximieren, und suchen Sie nach der Untergruppe „Arbeitsspeicher“.
- Tracks analysieren:
- mem.rss.anon (anonymer RSS): Dieses Liniendiagramm zeigt den physischen RAM in Echtzeit , der von den nicht verwalteten Arbeitsspeicherpools Ihres Spiels belegt wird. Beobachten Sie diese Zeitachse während des Ladens von Szenen, UI-Pop-ups oder Gameplay-Übergängen, um nach hohen Zuweisungsspitzen zu suchen.
- mem.swap (komprimierte Auslagerung oder VmSwap): In diesem Diagramm wird die vorkomprimierte Größe der Arbeitsspeicherblöcke dargestellt, die in zRAM verschoben wurden. Eine hohe Auslagerungsaktivität in Verbindung mit dem Gameplay deutet darauf hin, dass Ihr Spiel auf einem Gerät mit begrenztem Arbeitsspeicher ausgeführt wird und das System Hintergrundressourcen aktiv komprimiert.
2. SQL-Abfragen ausführen (Trace Processor) Für eine detaillierte Offlineanalyse können Sie SQL-Abfragen direkt in der Perfetto UI-Konsole ausführen oder die eigenständige Trace Processor Python-Bibliothek verwenden, um statistische Spitzen zu berechnen.
Maximale anonyme RSS-Zuweisung suchen:
SELECT max(value) / 1024 / 1024 AS max_rss_anon_mb FROM counter JOIN counter_track ON counter.track_id = counter_track.id WHERE counter_track.name = 'mem.rss.anon' AND counter_track.upid IN ( SELECT upid FROM process WHERE name = 'your.game.package.name' );RssAnon und VmSwap zu einem bestimmten Zeitstempel korrelieren:
SELECT ts, track.name AS metric_type, value / 1024 / 1024 AS size_mb FROM counter JOIN counter_track track ON counter.track_id = track.id WHERE (track.name = 'mem.rss.anon' OR track.name = 'mem.swap') AND track.upid IN ( SELECT upid FROM process WHERE name = 'your.game.package.name' ) ORDER BY ts ASC;
Weitere Informationen zum Prüfen von Trace-Dateien mit Android Studio finden Sie unter System-Traces prüfen: Prozessarbeitsspeicher (RSS). Details zum Scripting von Arbeitsspeicher profilen finden Sie unter Native Zuweisungen aufzeichnen.
heapprofd
heapprofd ist ein Tool zur Arbeitsspeicherverfolgung, das Teil von Perfetto ist. Mit diesem Tool können Sie Arbeitsspeicherlecks finden, indem Sie sehen, wo Arbeitsspeicher mit malloc zugewiesen wurde. heapprofd kann mit einem Python-Skript gestartet werden. Da das Tool einen geringen Aufwand verursacht, wirkt es sich nicht auf die Leistung aus wie andere Tools wie Malloc Debug.
bugreport
bugreport ist ein Logging-Tool, mit dem Sie herausfinden können, ob Ihr Spiel aufgrund von Arbeitsspeichermangel abgestürzt ist. Die Ausgabe des Tools ist viel detaillierter als bei Verwendung von logcat. Es ist nützlich für das Debugging von Arbeitsspeicherproblemen, da es zeigt, ob Ihr Spiel aufgrund von Out of Memory abgestürzt ist oder vom LMK beendet wurde.
Weitere Informationen finden Sie unter Fehlerberichte erfassen und lesen.
Tools für Spiel-Engines
Während Logs auf Plattformebene und Systemtelemetrie unerlässlich sind, um Betriebssystem-Grenzwerte und die Einhaltung von Richtlinien zu verfolgen, helfen Ihnen spiel-enginespezifische Tools, Zuweisungen direkt Ihren Spielobjekten, Skriptverhalten und aktiven Szenenhierarchien zuzuordnen.
Unity
In einer Unity Engine-Umgebung können Sie den Arbeitsspeicherbedarf von Android Anonymous RSS + Auslagerung zur Laufzeit mit hoher Zuverlässigkeit schätzen (in der Regel mit einer Abweichung von weniger als 10% im Vergleich zu echten Werten auf Betriebssystemebene), indem Sie die nativen Profiling-Tools und -Klassen von Unity verwenden.
Eine vollständige Schritt-für-Schritt-Anleitung mit Konfigurationsregeln und Laufzeit skripts finden Sie unter Arbeitsspeicher mit Unity-Tools prüfen.
- Unity Profiler API: Sie können den nicht verwalteten Speicherbedarf Ihres Spiels zur Laufzeit programmgesteuert schätzen, indem Sie die wichtigsten Engine-Messwerte abfragen:
- Profiler-Klasse verwenden: Verfolgen Sie die gesamten Arbeitsspeicherzuweisungen, indem Sie
die Werte von
Profiler.GetTotalReservedMemoryLong()undProfiler.GetMonoHeapSizeLong()addieren. - Klasse
ProfilerRecorderverwenden: Überwachen Sie Arbeitsspeicherkategorien dynamisch. Um eine zuverlässige Baseline-Schätzung zu erstellen, rufen Sie den gesamten reservierten Arbeitsspeicher (für Release-Builds) ab oder subtrahieren Sie den reservierten Grafikarbeitsspeicher (für Entwicklungs-Builds), um dateigestützte Grafikarbeitsspeicherkomponenten zu entfernen.
- Profiler-Klasse verwenden: Verfolgen Sie die gesamten Arbeitsspeicherzuweisungen, indem Sie
die Werte von
- Unity Memory Profiler: Wenn Sie Arbeitsspeicherlecks offline identifizieren und debuggen möchten,
erfassen Sie einen Arbeitsspeicher-Snapshot und prüfen Sie das Diagramm „Resident Memory on Device“
im Abschnitt „All of Memory“. Um den ungefähren Arbeitsspeicherbedarf zu berechnen, addieren Sie die Summen der folgenden Kategorien: „Untracked“, „Android Runtime“, „Native“ und „Managed“.
- zRAM-Einschränkung: Bei geringem Arbeitsspeicher kann der Android-Kernel inaktive Arbeitsspeicherseiten in den Auslagerungsspeicher (zRAM) komprimieren. Da der Unity Speicher-Profiler keine Auslagerungsparameter auf Betriebssystemebene erkennen kann, können bei Szenen mit hohem Arbeitsspeicherbedarf geringfügige Abweichungen beim Arbeitsspeicherbedarf auftreten. Vergleichen Sie Ihre Schätzungen mit Perfetto, um genaue Werte zu erhalten.