Android 17 und höher unterstützt den Memory Limiter, einen Systemdienst, der die Arbeitsspeichernutzung von Anwendungsprozessen mithilfe von Linux cgroup v2 überwacht und begrenzt. Der Memory Limiter verhindert, dass einzelne Apps zu viel Systemspeicher verbrauchen. Dadurch wird der systemspezifische Speicherbedarf reduziert und das aggressive Beenden kritischer Prozesse aufgrund von Speichermangel (Out-of-Memory, OOM) verhindert.
Mechanismus
Der Memory Limiter ist in den Activity Manager Service (AMS) integriert, um Ereignisse im Lebenszyklus von Prozessen und Statusänderungen zu verfolgen. Der Memory Limiter erzwingt Speicherlimits mithilfe des Linux-Kernel-Dateisystems cgroup v2.
Damit der Memory Limiter verwendet werden kann, muss der Gerätekernel cgroup v2 und den memory-Controller unterstützen. Der Dienst basiert speziell auf den folgenden Attributen:
memory.high- Ein weiches Limit. Wenn es überschritten wird, wird der Prozess gedrosselt und der Kernel versucht, Speicher freizugeben.
memory.swap.max- Begrenzt die Menge an Auslagerungsspeicher, die der Prozess verwenden kann.
Auswirkungen auf Apps
Apps, die ihre Speicherlimits nicht überschreiten, sind vom Memory Limiter nicht betroffen.
Wenn eine App das Limit memory.high überschreitet, entfernt der Kernel den dateibasierten Speicher der App und lagert den anonymen Speicher aus, damit die App das Limit nicht überschreitet. Aufgrund des Entfernens und Auslagerns wird die App möglicherweise langsamer ausgeführt.
Im Extremfall kann es passieren, dass die App weiterhin anonymen Speicher zuweist und der Auslagerungsspeicher des Geräts erschöpft ist. In diesem Fall kann die App keinen Speicher mehr zuweisen und stürzt wahrscheinlich ab.
Prozessmonitoring
Der Memory Limiter überwacht standardmäßig App-Prozesse (UID >= 10000). Systemprozesse sind in der Regel ausgenommen, um die Stabilität des Kernsystems zu überprüfen.
Der Memory Limiter weist Speicherlimits basierend auf dem Status des Prozesses zu:
Sichtbare Prozesse sind für den Nutzer wahrnehmbar, z. B. Aktivitäten im Vordergrund, Dienste im Vordergrund oder andere Zustände, die zu Rucklern führen können.
Nicht sichtbare Prozesse sind Hintergrundprozesse, die nicht mit dem Nutzer interagieren oder für ihn sichtbar sind.
In der folgenden Tabelle werden bestimmte Prozesszustände Speicherlimits zugeordnet:
| Prozessstatus | Arbeitsspeicherlimit |
|---|---|
PERSISTENT | Uneingeschränkt |
PERSISTENT_UI | Uneingeschränkt |
TOP | Sichtbar |
BOUND_TOP | Sichtbar |
FOREGROUND_SERVICE | Nicht sichtbar |
BOUND_FOREGROUND_SERVICE | Nicht sichtbar |
IMPORTANT_FOREGROUND | Sichtbar |
IMPORTANT_BACKGROUND | Nicht sichtbar |
TRANSIENT_BACKGROUND | Nicht sichtbar |
BACKUP | Nicht sichtbar |
SERVICE | Nicht sichtbar |
RECEIVER | Nicht sichtbar |
TOP_SLEEPING | Sichtbar |
HEAVY_WEIGHT | Nicht sichtbar |
HOME | Nicht sichtbar |
LAST_ACTIVITY | Nicht sichtbar |
CACHED_ACTIVITY | Im Cache gespeichert |
CACHED_ACTIVITY_CLIENT | Im Cache gespeichert |
CACHED_RECENT | Im Cache gespeichert |
CACHED_EMPTY | Im Cache gespeichert |
Im Cache gespeicherte Prozesse werden eingefroren und dann maximal freigegeben.
Wenn ein Prozess das zugewiesene Limit memory.high überschreitet, erkennt der Memory Limiter das Ereignis und kann Debugging-Aktionen auslösen, z. B. ein Speicherprofil erfassen oder eine Anomalie in statsd protokollieren.
Konfiguration
Konfigurieren Sie den Memory Limiter mit einer XML-Datei auf der Partition vendor. Mit der Konfiguration können Sie absolute Speicherlimits basierend auf den spezifischen Speicherbeschränkungen des Geräts anpassen.
Dateipfad:
/vendor/etc/memory-limiter-config.xmlStandardkonfiguration:Wenn die Konfigurationsdatei nicht gefunden wird oder nicht lesbar oder ungültig ist, wird der Memory Limiter deaktiviert.
XML-Format
Die Konfigurationsdatei folgt dem in memory-limiter-config.xsd definierten Schema. In der Datei können Sie mehrere Limitsätze definieren. Der Dienst wählt basierend auf dem verfügbaren RAM des Geräts die beste Übereinstimmung aus. Alle Speicherwerte werden in Mebibyte (MiB) angegeben.
<MemoryLimiterConfig>
<version>1</version>
<configList>
<limitSet>
<!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
<minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
</configList>
</MemoryLimiterConfig>
version- Eine positive Ganzzahl, die die Konfigurationsversion angibt. Muss 1 sein.
minimumRequiredMemTotal- Der mindestens erforderliche verfügbare Systemspeicher, damit dieser Limitsatz gültig ist.
memVisible- Das Speicherlimit (
memory.high), das für sichtbare Prozesse zulässig ist. memNotVisible- Das Speicherlimit (
memory.high), das für nicht sichtbare Prozesse zulässig ist. swapVisible- Das Auslagerungslimit (
memory.swap.max), das für sichtbare Prozesse zulässig ist. swapNotVisible- Das Auslagerungslimit (
memory.swap.max), das für nicht sichtbare Prozesse zulässig ist.
Konfiguration ändern
So ändern Sie systemweite Limits:
- Ändern Sie
/vendor/etc/memory-limiter-config.xml. - Starten Sie das Gerät neu oder starten Sie
system_serverneu, damit die Änderungen wirksam werden.
Shell-Befehle
Mit dem Befehl am memory-limiter können Sie und Entwickler zur Laufzeit mit dem Dienst interagieren, um ihn zu entwickeln und zu testen:
am memory-limiter <SUB-COMMAND>Status
Der Unterbefehl status gibt den Betriebsstatus des Memory Limiters an:
adb shell am memory-limiter statusBeispielausgabe:
Memory limiter
enabled monitoring=true ignored=none
visibleMem=1948MB visibleSwap=974MB
notVisibleMem=974MB notVisibleSwap=487MB
started=36 watched=36 watch-failed=0
events=0 processes=36 process-hwm=36
Wichtige Felder in der Ausgabe sind:
monitoring- Gibt an, ob der Limiter Prozesse aktiv überwacht.
visibleMemundnotVisibleMem- Geben die berechneten absoluten Speicherlimits für jeden Status an.
events- Die Anzahl der Male, die ein Prozess sein Limit überschritten hat.
processes- Die Anzahl der überwachten Prozesse.
Ignorieren
Mit dem Unterbefehl ignore können Sie eine UID oder alle Prozesse vorübergehend von der Begrenzung ausschließen. Diese Aktion ist nützlich für Leistungstests oder wenn eine bestimmte App ihre Limits überschreiten darf.
adb shell am memory-limiter ignore 10087 // Ignore a specific UIDadb shell am memory-limiter ignore all // Ignore all processes (effectively disables limiting)adb shell am memory-limiter ignore none // Resume normal operation
Manuell
Mit dem Unterbefehl manual können Sie die berechneten Limits für einen bestimmten Prozess (nach Prozess-ID oder PID) mit einem benutzerdefinierten absoluten Wert in Megabyte (MB) überschreiben:
adb shell am memory-limiter manual 1234 1024 // Set a 1024 MB limit for PID 1234adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234
Manuelle Überschreibungen gelten nur für den Lebenszyklus des Prozesses. Wenn der Prozess neu gestartet wird, werden die Standardlimits basierend auf seinem Status wiederhergestellt.