Arbeitsspeicherbegrenzer

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 Arbeitsspeicherbegrenzer verhindert, dass einzelne Apps zu viel Systemspeicher verbrauchen. Dadurch wird der systemspezifische Arbeitsspeicherbedarf reduziert und das aggressive Beenden wichtiger Prozesse aufgrund von Arbeitsspeichermangel (Out-of-Memory, OOM) verhindert.

Mechanismus

Der Memory Limiter ist in den Activity Manager Service (AMS) integriert, um Ereignisse im Prozesslebenszyklus und Statusänderungen zu verfolgen. Der Memory Limiter erzwingt Arbeitsspeicherlimits mithilfe des Linux-Kernel-Dateisystems „cgroup v2“.

Damit der Memory Limiter verwendet werden kann, muss der Geräte-Kernel cgroup v2 und den memory-Controller unterstützen. Der Dienst basiert insbesondere auf den folgenden Attributen:

memory.high
Ein weiches Limit. Wird das Limit überschritten, wird der Prozess gedrosselt und der Kernel versucht, Arbeitsspeicher zurückzugewinnen.
memory.swap.max
Begrenzt die Menge an Auslagerungsspeicher, die der Prozess verwenden kann.

Auswirkungen auf Apps

Apps, die ihre Arbeitsspeicherlimits nicht überschreiten, sind vom Memory Limiter nicht betroffen.

Wenn eine App ihr memory.high-Limit überschreitet, entfernt der Kernel den dateibasierten Speicher der App und tauscht den anonymen Speicher aus, damit die App das Limit nicht überschreitet. Durch das Entfernen und Ersetzen kann es sein, dass die App langsamer ausgeführt wird.

Wenn die App weiterhin anonymen Arbeitsspeicher zuweist und auf dem Gerät kein Swap-Speicher mehr verfügbar ist, kann es im Extremfall passieren, dass die App keinen Arbeitsspeicher mehr zuweisen kann und abstürzt.

Prozessmonitoring

Der Arbeitsspeicherbegrenzer ü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 Arbeitsspeicherlimits basierend auf dem Status des Prozesses zu:

  • Sichtbare Prozesse befinden sich in einem Zustand, in dem sie dem Nutzer eine Benutzeroberfläche anzeigen können. Wenn ein Prozess eine Benutzeroberfläche anzeigt, wird möglicherweise ein größerer RAM-Arbeitssatz erwartet. Daher wird ihm ein großzügigeres Arbeitsspeicherlimit gewährt.

  • Nicht sichtbare Prozesse sind in einem Zustand, in dem sie aktiv Aufgaben ausführen, aber keine Benutzeroberfläche darstellen. Sie benötigen dafür Speicher, aber weniger als für die Anzeige einer Benutzeroberfläche. Daher gilt für sie ein restriktiveres Limit.

In der folgenden Tabelle werden bestimmte Prozessstatus den Arbeitsspeicherlimits zugeordnet:

ProzessstatusArbeitsspeicherlimit
PERSISTENTUneingeschränkt
PERSISTENT_UIUneingeschränkt
TOPSichtbar
BOUND_TOPSichtbar
FOREGROUND_SERVICENicht sichtbar
BOUND_FOREGROUND_SERVICENicht sichtbar
IMPORTANT_FOREGROUNDSichtbar
IMPORTANT_BACKGROUNDNicht sichtbar
TRANSIENT_BACKGROUNDNicht sichtbar
BACKUPNicht sichtbar
SERVICENicht sichtbar
RECEIVERNicht sichtbar
TOP_SLEEPINGSichtbar
HEAVY_WEIGHTNicht sichtbar
HOMENicht sichtbar
LAST_ACTIVITYNicht sichtbar
CACHED_ACTIVITYIm Cache
CACHED_ACTIVITY_CLIENTIm Cache
CACHED_RECENTIm Cache
CACHED_EMPTYIm Cache

Im Cache-Zustand werden Prozesse eingefroren und dann maximal zurückgefordert.

Wenn ein Prozess das zugewiesene memory.high-Limit ü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 an die spezifischen Speicherbeschränkungen des Geräts anpassen.

  • Dateipfad: /vendor/etc/memory-limiter-config.xml

  • Standardkonfiguration:Wenn die Konfigurationsdatei nicht gefunden wird oder nicht lesbar oder ungültig ist, wird der Memory Limiter deaktiviert.

XML-Format

Die Konfigurationsdatei entspricht dem in memory-limiter-config.xsd definierten Schema. In der Datei können Sie mehrere Grenzwertsätze definieren. Der Dienst wählt den besten Satz basierend auf dem verfügbaren RAM des Geräts 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 dieses Limit gültig ist.
memVisible
Das für sichtbare Prozesse zulässige Speicherlimit (memory.high).
memNotVisible
Das für nicht sichtbare Prozesse zulässige Arbeitsspeicherlimit (memory.high).
swapVisible
Das für sichtbare Prozesse zulässige Swap-Limit (memory.swap.max).
swapNotVisible
Das Swap-Limit (memory.swap.max) wurde für nicht sichtbare Prozesse überschritten.

Richtlinien für das Speicherlimit von Geräten

Beachten Sie beim Konfigurieren von Arbeitsspeicherlimits für Ihr Gerät die folgenden Richtlinien:

  • Grenzwerte an Hardwarefunktionen anpassen:Geräte-OEMs können Grenzwerte festlegen, die auf die Hardwarefunktionen ihrer Geräte zugeschnitten sind. Android empfiehlt die folgenden Bereiche:

    • Sichtbare Prozesse:Mindestens die Hälfte und höchstens zwei Drittel des gesamten physischen RAM.
    • Nicht sichtbare Prozesse:1/4 bis 1/3 des gesamten physischen RAM. OEMs können je nach Gerätefunktionen und Anwendungsfällen unterschiedliche Entscheidungen treffen.
  • Keine Laufzeit-API für Apps:Ab Android 17 (SDK 37) haben Apps keine API mehr, um die Speicherlimits zur Laufzeit abzufragen. OEMs sollten dies berücksichtigen und vermeiden, Limits zu niedrig festzulegen, damit Apps bei angemessenen Anwendungsfällen nicht an die Limits stoßen.

  • Universelle Konfiguration:Die Limits gelten für alle App-Prozesse auf dem Gerät, einschließlich vorinstallierter Apps. Es gibt keine Zulassungsliste, um bestimmte Apps von diesen Einschränkungen auszunehmen.

Konfiguration ändern

So ändern Sie systemweite Limits:

  1. /vendor/etc/memory-limiter-config.xml ändern
  2. Starte das Gerät neu oder starte system_server neu, 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 zurück:

adb shell am memory-limiter status

Beispielausgabe:

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:

monitoring
Gibt an, ob der Limiter Prozesse aktiv überwacht.
visibleMem und notVisibleMem
Geben Sie die berechneten absoluten Speicherlimits für jeden Bundesstaat an.
events
Die Häufigkeit, mit der ein Prozess sein Limit überschritten hat.
processes
Die Anzahl der überwachten Prozesse.

ignorieren

Mit dem Unterbefehl ignore wird eine UID oder alle Prozesse vorübergehend von der Einschränkung ausgeschlossen. 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 UID
adb 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 werden die berechneten Grenzwerte für einen bestimmten Prozess (nach Prozess-ID oder PID) mit einem benutzerdefinierten absoluten Wert in Megabyte (MB) überschrieben:

adb shell am memory-limiter manual 1234 1024   // Set a 1024 MB limit for PID 1234
adb 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 dem Status wiederhergestellt.