Überblick über die Speicherverwaltung

Die Android-Laufzeitumgebung (ART) und die virtuelle Dalvik-Maschine verwenden Paging und Memory-Mapping (mmapping) zur Speicherverwaltung. Das bedeutet, dass jeder Speicher, den eine Anwendung verändert – sei es durch Zuweisung neuer Objekte oder durch Berühren von mmapped pages – im RAM verbleibt und nicht ausgelagert werden kann. Die einzige Möglichkeit, Speicher aus einer Anwendung freizugeben, besteht darin, Objektreferenzen freizugeben, die die Anwendung hält, und so den Speicher für den Garbage Collector verfügbar zu machen. Dies gilt mit einer Ausnahme: Dateien, die ohne Änderung eingeblendet werden, wie z. B. Code, können aus dem RAM ausgelagert werden, wenn das System diesen Speicher anderweitig verwenden möchte.

Diese Seite erklärt, wie Android App-Prozesse und Speicherzuweisungen verwaltet. Weitere Informationen darüber, wie Sie den Speicher in Ihrer App effizienter verwalten können, finden Sie unter Verwalten des Speichers Ihrer App.

Garbage Collection

Eine verwaltete Speicherumgebung, wie die virtuelle Maschine ART oder Dalvik, verfolgt jede Speicherzuweisung. Sobald sie feststellt, dass ein Teil des Speichers nicht mehr vom Programm verwendet wird, gibt sie ihn wieder für den Heap frei, ohne dass der Programmierer eingreifen muss. Der Mechanismus zur Rückgewinnung von ungenutztem Speicher in einer verwalteten Speicherumgebung wird als Garbage Collection bezeichnet. Die Garbage Collection verfolgt zwei Ziele: Datenobjekte in einem Programm zu finden, auf die in Zukunft nicht mehr zugegriffen werden kann, und die von diesen Objekten verwendeten Ressourcen zurückzufordern.

Androids Speicherheap ist ein Generationsheap, d. h. es gibt verschiedene Bereiche für Zuweisungen, die je nach erwarteter Lebensdauer und Größe eines zugewiesenen Objekts verfolgt werden. Kürzlich zugewiesene Objekte gehören zum Beispiel in die Young-Generation. Wenn ein Objekt lange genug aktiv bleibt, kann es in eine ältere Generation befördert werden, gefolgt von einer permanenten Generation.

Jede Heap-Generation hat eine eigene Obergrenze für die Menge an Speicher, die Objekte dort belegen können. Jedes Mal, wenn eine Generation anfängt, sich zu füllen, führt das System eine Garbage Collection durch, um Speicher freizugeben. Die Dauer der Garbage Collection hängt davon ab, welche Generation von Objekten gesammelt wird und wie viele aktive Objekte sich in jeder Generation befinden.

Auch wenn die Garbage Collection recht schnell sein kann, kann sie die Leistung Ihrer Anwendung beeinträchtigen. In der Regel haben Sie in Ihrem Code keinen Einfluss darauf, wann ein Garbage Collection-Ereignis eintritt. Das System verfügt über eine Reihe von Kriterien, die bestimmen, wann eine Garbage Collection durchgeführt werden soll. Wenn die Kriterien erfüllt sind, hält das System die Ausführung des Prozesses an und beginnt mit der Garbage Collection. Wenn die Garbage Collection in der Mitte einer intensiven Verarbeitungsschleife wie einer Animation oder während der Musikwiedergabe stattfindet, kann sich die Verarbeitungszeit verlängern. Dieser Anstieg kann dazu führen, dass die Codeausführung in Ihrer Anwendung den empfohlenen Schwellenwert von 16 ms für eine effiziente und reibungslose Bildwiedergabe überschreitet.

Außerdem kann Ihr Codefluss Arbeiten ausführen, die dazu führen, dass Garbage Collection-Ereignisse häufiger auftreten oder länger als normal dauern. Wenn Sie zum Beispiel mehrere Objekte im innersten Teil einer for-Schleife während jedes Frames einer Alpha-Blending-Animation zuweisen, könnten Sie Ihren Speicherheap mit einer Menge von Objekten verschmutzen. In diesem Fall führt der Garbage-Collector mehrere Garbage-Collection-Ereignisse aus und kann die Leistung Ihrer Anwendung beeinträchtigen.

Weitere allgemeine Informationen zur Garbage-Collection finden Sie unter Garbage-Collection.

Speicher gemeinsam nutzen

Um alles, was im RAM benötigt wird, unterzubringen, versucht Android, RAM-Seiten prozessübergreifend zu nutzen. Es kann dies auf folgende Weise tun:

  • Jeder App-Prozess wird von einem bestehenden Prozess namens Zygote abgezweigt. Der Zygote-Prozess startet, wenn das System hochfährt und lädt gemeinsamen Framework-Code und Ressourcen (wie Aktivitäts-Themen). Um einen neuen Anwendungsprozess zu starten, forkt das System den Zygote-Prozess, lädt den Code der Anwendung und führt ihn im neuen Prozess aus. Auf diese Weise können die meisten RAM-Seiten, die für den Framework-Code und die Ressourcen vorgesehen sind, von allen App-Prozessen gemeinsam genutzt werden.
  • Die meisten statischen Daten werden in einem Prozess abgebildet. Diese Technik ermöglicht die gemeinsame Nutzung von Daten zwischen Prozessen und erlaubt es auch, sie bei Bedarf auszulagern. Beispiele für statische Daten sind: Dalvik-Code (durch Platzierung in einer vorverlinkten .odex-Datei für direktes mmapping), App-Ressourcen (durch Gestaltung der Ressourcentabelle als Struktur, die mmapped werden kann, und durch Ausrichten der Zip-Einträge der APK) und traditionelle Projektelemente wie nativer Code in .so-Dateien.
  • An vielen Stellen teilt Android prozessübergreifend denselben dynamischen Arbeitsspeicher mit explizit zugewiesenen gemeinsamen Speicherbereichen (entweder mit ashmem oder gralloc). Zum Beispiel verwenden Fensteroberflächen gemeinsamen Speicher zwischen der App und dem Screen Compositor, und Cursorpuffer verwenden gemeinsamen Speicher zwischen dem Inhaltsanbieter und dem Client.

Aufgrund der umfangreichen Verwendung von gemeinsamem Speicher ist es wichtig zu bestimmen, wie viel Speicher Ihre Anwendung verwendet. Techniken zur korrekten Bestimmung des Speicherverbrauchs Ihrer Anwendung werden in Untersuchung der RAM-Nutzung besprochen.

Zuweisung und Rückforderung von Anwendungsspeicher

Der Dalvik-Heap ist auf einen einzigen virtuellen Speicherbereich für jeden Anwendungsprozess beschränkt. Dies definiert die logische Heap-Größe, die nach Bedarf wachsen kann, aber nur bis zu einer Grenze, die das System für jede Anwendung festlegt.

Die logische Größe des Heaps ist nicht identisch mit der Menge des physischen Speichers, der vom Heap verwendet wird. Bei der Überprüfung des Heaps einer App berechnet Android einen Wert namens Proportional Set Size (PSS), der sowohl schmutzige als auch saubere Seiten berücksichtigt, die mit anderen Prozessen geteilt werden – aber nur in einem Umfang, der proportional dazu ist, wie viele Apps sich diesen RAM teilen. Diese (PSS-)Summe ist das, was das System als Ihren physischen Speicherbedarf betrachtet. Weitere Informationen zu PSS finden Sie im Leitfaden Investigating Your RAM Usage.

Der Dalvik-Heap kompaktiert die logische Größe des Heaps nicht, was bedeutet, dass Android den Heap nicht defragmentiert, um Speicherplatz zu schließen. Android kann die logische Heap-Größe nur verkleinern, wenn am Ende des Heaps ungenutzter Platz vorhanden ist. Das System kann jedoch den vom Heap verwendeten physischen Speicher reduzieren. Nach der Garbage Collection durchläuft Dalvik den Heap und findet ungenutzte Seiten, die dann mit madvise an den Kernel zurückgegeben werden. Gepaarte Allokationen und Deallokationen von großen Chunks sollten also dazu führen, daß der gesamte (oder fast der gesamte) verwendete physische Speicher zurückgewonnen wird. Allerdings kann die Rückgewinnung von Speicher aus kleinen Zuweisungen viel weniger effizient sein, da die Seite, die für eine kleine Zuweisung verwendet wird, noch mit etwas anderem geteilt werden kann, das noch nicht freigegeben wurde.

Beschränken Sie den App-Speicher

Um eine funktionierende Multitasking-Umgebung aufrechtzuerhalten, setzt Android eine harte Grenze für die Heap-Größe für jede App. Die genaue Begrenzung der Heap-Größe variiert von Gerät zu Gerät und hängt davon ab, wie viel RAM das Gerät insgesamt zur Verfügung hat. Wenn Ihre App die Heap-Kapazität erreicht hat und versucht, mehr Speicher zuzuweisen, kann sie eine OutOfMemoryError erhalten.

In manchen Fällen möchten Sie vielleicht das System abfragen, um genau zu bestimmen, wie viel Heap-Speicherplatz Sie auf dem aktuellen Gerät zur Verfügung haben, um beispielsweise zu ermitteln, wie viele Daten sicher in einem Cache gespeichert werden können. Sie können das System nach dieser Zahl abfragen, indem Sie getMemoryClass() aufrufen. Diese Methode gibt eine ganze Zahl zurück, die die Anzahl der Megabytes angibt, die für den Heap Ihrer App verfügbar sind.

Apps wechseln

Wenn Benutzer zwischen Apps wechseln, behält Android Apps, die nicht im Vordergrund sind – also nicht für den Benutzer sichtbar sind oder einen Vordergrunddienst wie Musikwiedergabe ausführen – in einem Cache. Wenn ein Benutzer zum Beispiel eine App zum ersten Mal startet, wird ein Prozess dafür erstellt; aber wenn der Benutzer die App verlässt, wird dieser Prozess nicht beendet. Das System behält den Prozess im Cache. Wenn der Benutzer später zu der Anwendung zurückkehrt, verwendet das System den Prozess erneut, wodurch die Anwendung schneller wechselt.

Wenn Ihre Anwendung einen Prozess im Cache hat und Ressourcen zurückhält, die sie derzeit nicht benötigt, beeinträchtigt Ihre Anwendung – auch wenn der Benutzer sie nicht benutzt – die Gesamtleistung des Systems. Wenn dem System die Ressourcen wie der Arbeitsspeicher ausgehen, werden die Prozesse im Cache beendet. Das System berücksichtigt auch Prozesse, die den meisten Arbeitsspeicher beanspruchen, und kann sie beenden, um Arbeitsspeicher freizugeben.

Anmerkung: Je weniger Arbeitsspeicher Ihre Anwendung im Cache verbraucht, desto besser sind die Chancen, dass sie nicht beendet wird und schnell wieder fortgesetzt werden kann. Abhängig von den momentanen Systemanforderungen ist es jedoch möglich, dass zwischengespeicherte Prozesse jederzeit beendet werden können, unabhängig von ihrer Ressourcenauslastung.

Weitere Informationen darüber, wie Prozesse zwischengespeichert werden, während sie nicht im Vordergrund laufen, und wie Android entscheidet, welche Prozesse beendet werden können, finden Sie im Leitfaden Prozesse und Threads.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.