Daemon für die Speicherverwaltung

Android 17 und höher unterstützt den Memory-Management-Daemon (mmd), einen System-Daemon, der sich um die Daemon-Konfiguration, die abstimmbaren Parameter und die laufenden Swap- oder ZRAM-Wartungsaufgaben kümmert.

Hintergrund

Vor der Einführung von mmd waren die ZRAM-Konfigurationen von Android fragmentiert und boten nur begrenzte Anpassungsmöglichkeiten. mmd behebt dieses Problem, indem die ZRAM-Verwaltung zentralisiert wird. So können komplexere Konfigurationslogiken verwendet und neue Funktionen und Architekturverbesserungen einfacher hinzugefügt werden. mmd sorgt auch für eine klare Trennung der Zuständigkeiten zwischen dem Java-basierten system_server-Prozess und dem Swap oder der Speicherverwaltung auf Kernelebene.

Architektur und ZRAM-Verwaltung

Nach Abschluss des Bootvorgangs (d. h. wenn sys.boot_completed=1) versucht mmd_setup, ZRAM mit den angegebenen Parametern zu konfigurieren. Nachdem die ZRAM-Einrichtung abgeschlossen ist, aktiviert das System den mmd-Dienst, der laufende Wartungsaufgaben übernimmt.

Im mmd-Projekt werden Wartungsvorgänge von system_server aus initiiert, indem Binder-Anfragen über die IMmd-Schnittstelle an mmd gesendet werden. mmd übernimmt die Wartungsaufgaben für das ZRAM-Writeback, die Re-Kompression und das prozessbezogene Writeback basierend auf der eigenen internen Richtlinien-Engine. Sowohl die Planung über ActivityManagerService als auch die ZRAM-Wartungsrichtlinien können über Systemeigenschaften konfiguriert werden.

System server integration (system_server)

Der Java-basierte system_server-Prozess bestimmt, wann mmd aufgerufen wird. Bei diesem Verfahren werden globale Wartungsdurchläufe von gezielten Speicheroptimierungen pro App getrennt.

Normale Wartung der Nachbearbeitung

Die globale ZRAM-Wartung wird vom ActivityManagerService mit com.android.server.memory.ZramMaintenance gesteuert.

zram-maintenance

Abbildung 1. Ablauf für die ZRAM-Wartungsplanung.

  • Planungsmodul:ZramMaintenance registriert einen regelmäßigen Hintergrundjob mit JobScheduler von Android.
  • Job-Einschränkungen:Um Ruckeln der Benutzeroberfläche im Vordergrund oder CPU-Konflikte zu vermeiden, wird der Job explizit mit setRequiresDeviceIdle(true) und setRequiresBatteryNotLow(true) konfiguriert.
  • Binder-Auslösung:Wenn der Scheduler onStartJob() auslöst, ruft system_server mmd.doZramMaintenanceAsync() auf. Dies ist ein unidirektionaler asynchroner Binder-Aufruf. system_server blockiert nicht und wartet nicht, bis die Wartungsdurchläufe abgeschlossen sind. mmd stellt dies in die Warteschlange eines Hintergrund-Worker-Threads, um die Neukomprimierung und das Zurückschreiben sequenziell auszuführen.

Rückschreiben pro Prozess

Das gezielte Entfernen von Arbeitsspeicher pro Prozess wird vom ActivityManagerService über com.android.server.am.CachedAppOptimizer verwaltet.

mmd-writeback

Abbildung 2: MMD-Writeback-Ablauf pro Prozess.

Wenn ein Prozess in den Hintergrund-Cache-Status wechselt, führt ActivityManager eine Speicherverdichtung durch. Wenn ein Low-Memory-Kill des Prozesses für den Nutzer sichtbar wäre, d. h. der Prozess hostet eine Aktivität, und wenn der prozessbezogene ZRAM-Writeback den Speicherbedarf des Prozesses auf nahezu null reduzieren würde, führt das System die folgenden Schritte aus:

  1. Nach der Komprimierung sendet CachedAppOptimizer eine verzögerte Nachricht (ZRAM_WRITEBACK_MSG) an den internen Komprimierungs-Handler (verzögert um mZramWritebackWaitSeconds).
  2. Wenn die Verzögerung abgelaufen ist, öffnet ActivityManager einen sicheren Prozessdateideskriptor pidfd.
  3. Der Systemserver ruft mmd.asyncWritebackProcessZramMemory(pfd, callback) auf.
  4. mmd führt den prozessbezogenen Writeback-ioctl aus und meldet das Ergebnis über IMmdProcessWritebackCallback. Bei Erfolg kennzeichnet ActivityManager den Prozessdatensatz (setIsZramWrittenBack(app, true)), um die oom_score_adj des Prozesses zu steigern, und protokolliert Messwerte in FrameworkStatsLog.ZRAM_WRITEBACK_EVENT.

Prefetch pro Prozess

Wenn ein Nutzer eine zuvor im Cache gespeicherte App neu startet (die aufgrund von UNFREEZE_REASON_ACTIVITY reaktiviert wurde), minimiert ActivityManager die App-Startlatenz, die durch schwerwiegende Seitenfehler aus dem Sicherungsspeicher verursacht wird:

  1. CachedAppOptimizer fängt das Ereignis zum Aufheben des Einfrierens ab und ruft prefetchZram(app) auf.
  2. Der Systemserver sendet die pidfd der App über Binder mit mmd.asyncPrefetchProcessZramMemory(pfd). mmd gibt den ioctl ZRAM_ANDROID_IOC_PROCESS_PREFETCH aus und weist den Kernel an, ausgelagerte Seiten asynchron wieder in den RAM vorab abzurufen, während der Haupt-UI-Thread der App initialisiert wird.

Übersicht über Wartungs- und Nachbearbeitungsaufgaben

In diesem Abschnitt werden die Hintergrundwartungsvorgänge und Nachbearbeitungsaufgaben beschrieben, die von mmd ausgeführt werden, um den Swap-Speicher und den Systemspeicher zu optimieren.

Wartung in mmd

In mmd bezieht sich Wartung auf geplante Hintergrundwartungsdurchläufe, die die Nutzung von Swap-Space und physischem Arbeitsspeicher optimieren, ohne die Leistung aktiver Nutzer im Vordergrund zu beeinträchtigen. Anstatt kontinuierliche, synchrone Sweeps durchzuführen, die zu starken CPU-Aktivierungen und UI-Rucklern führen würden, wird die Wartung asynchron ausgeführt:

  1. system_server löst regelmäßig doZramMaintenanceAsync() in Binder aus.

  2. mmd stellt die Anfrage in eine Warteschlange für Hintergrundaufgaben LowPrioWorkItem::ZramMaintenance.

  3. In mmd gibt es einen einzelnen Worker-Thread, der sowohl eine Warteschlange mit hoher Priorität als auch eine Warteschlange mit niedriger Priorität verwaltet. Arbeitselemente mit hoher Priorität (z. B. das Vorabrufen pro Prozess) werden zuerst verarbeitet und können Arbeitselemente mit niedriger Priorität unterbrechen. Wartung und prozessbezogenes Zurückschreiben werden als Arbeitselemente mit niedriger Priorität ausgeführt. Wenn der Arbeitsthread gestartet wird, führt er zwei primäre Wartungsvorgänge sequenziell aus:

    • ZRAM-Neukomprimierung:Durchsucht vorhandene Swap-Seiten und komprimiert inaktive Seiten mit einem sekundären Komprimierungsalgorithmus mit höherem Verhältnis, z. B. zstd.

    • ZRAM-Writeback:Scannt inaktive Seiten und entfernt sie vollständig aus dem RAM in den Sicherungs-Flash-Speicher eines Loop-Geräts aus einer Datei auf /data.

Nachbearbeitungsaufgaben in ZRAM

Im Linux-Kernel-ZRAM-Modul und in der mmd-Architektur sind Nachbearbeitungsaufgaben die asynchronen Transformationen, die auf Speicherseiten angewendet werden, nachdem sie bereits über die standardmäßigen Reclaim-Pfade des Kernels (kswapd oder Verdichtung) ausgelagert wurden.

Wenn eine Seite zum ersten Mal ausgelagert wird, priorisiert das System die Geschwindigkeit: Es verwendet einen schnellen primären Komprimierungsalgorithmus (wie lz4) und speichert die komprimierte Seite im RAM. Im Laufe der Zeit werden jedoch viele ausgelagerte Seiten inaktiv, z. B. im Hintergrund zwischengespeicherte Apps, die stundenlang nicht fortgesetzt werden. Das Speichern von inaktiven Seiten in schnellem, leicht komprimiertem ZRAM ist ineffizient.

Pipeline für die Nachbearbeitung

mmd implementiert einen mehrstufigen Nachbearbeitungszyklus, um diese Seiten zu optimieren:

mmd-page-lifecycle

Abbildung 3: mmd-Seitenlebenszyklus.

  1. Phase 1: Erster Swap-Out (schnelle Komprimierung): Der Arbeitsspeicher wird zuerst durch kswapd oder die App-Kompaktierung freigegeben. In der Regel wird diese erste Rückforderung mit einem schnellen Komprimierungsalgorithmus wie lz4 durchgeführt und der Inhalt wird im RAM gespeichert.

  2. Phase 2: Markierung im Leerlauf (Alterung und Tracking): mmd-Leerlauf-Tracking greift auf den Kernel-Speicher-Tracker (CONFIG_ZRAM_TRACK_ENTRY_ACTIME) zu oder verwendet seinen Software-Leerlauf-Marker, um zu verfolgen, wie lange Seiten nicht verwendet wurden.

  3. Phase 3: Nachbearbeitung 1 – Re-Kompression (Speicheroptimierung im Arbeitsspeicher): Seiten, die das Leerlaufalter für die Re-Kompression (min_idle_seconds bis max_idle_seconds) erreichen, werden neu komprimiert. mmd schreibt in /sys/block/zram0/recompress, um den Kernel anzuweisen, die Seite lz4 zu dekomprimieren und mit zstd neu zu komprimieren. Dadurch wird physischer RAM zurückgewonnen, ohne dass der Flash-Speicher abgenutzt wird.

  4. Phase 4: Nachbearbeitung 2 – Zurückschreiben (Entfernen in den Flash-Speicher): Wenn der Speicherdruck anhält und Seiten das Alter für das Zurückschreiben im Leerlauf erreichen (in der Regel 20 Stunden oder mehr), löst mmd das Zurückschreiben aus. mmd schreibt in /sys/block/zram0/idle und /sys/block/zram0/writeback, um die komprimierte Seite vollständig aus dem RAM in den Sicherungs-Flash-Speicher zu verschieben.

ZRAM-Einrichtung konfigurieren

mmd lädt und verarbeitet die folgenden ZRAM-Einrichtungseigenschaften:

Attribut Verwenden Standard
mmd.zram.enabled Gibt an, ob die mmd-ZRAM-Einrichtung aktiviert ist. false
mmd.zram.num_devices Die Anzahl der zu konfigurierenden ZRAM-Geräte. Für die Nummer N müssen die Geräte zram0 bis zram<N-1> vorhanden sein, bevor das System sys.boot_completed=1 festlegt. Eigenschaften in der Liste der ZRAM-Geräte können gerätespezifisch konfiguriert werden. 1
mmd.zram.device_priority Prioritätswerte, die beim Aufrufen von swapon übergeben werden sollen. Nicht festgelegt
mmd.zram.comp_algorithm ZRAM-Komprimierungsalgorithmus. Wenn nicht angegeben, wird der Standardkomprimierungsalgorithmus des Kernels verwendet. Nicht festgelegt
mmd.zram.size Die Größe des ZRAM-Geräts in Byte oder ein Prozentsatz der RAM-Größe des Geräts, z. B. 75%. 50%
mmd.zram.writeback.enabled Gibt an, ob ZRAM-Writeback aktiviert werden soll. false
mmd.zram.writeback.device_size Die Größe des Writeback-Geräts in Byte oder als Prozentsatz der Datenpartition. Die tatsächliche Gerätegröße kann je nach verfügbarem Speicherplatz auf der Datenpartition angepasst werden. 1073741824 (1 GiB)
mmd.zram.writeback.min_free_space_mib Der minimale kostenlose Speicherplatz in MiB, der nach der Einrichtung des Writeback-Geräts verfügbar sein muss. 1536 (1,5 GiB)
mmd.zram.writeback.use_nr_tags_prop Wenn true, wird der Wert in mmd.zram.writeback.nr_tags verwendet, um die Warteschlangentiefe des Loop-Geräts zu konfigurieren, das ZRAM-Writeback unterstützt. Dies ist eine Problemumgehung für Situationen, in denen die SELinux-Richtlinie des Anbieters nicht so konfiguriert werden kann, dass mmd nr_tags des Blockgeräts, das /data unterstützt, direkt lesen kann. false
mmd.zram.writeback.nr_tags mmd.zram.writeback.use_nr_tags_prop ansehen. Nicht festgelegt
mmd.zram.recompression.enabled Gibt an, ob die ZRAM-Neukomprimierungsfunktion aktiviert werden soll. false
mmd.zram.recompression.algorithm Sekundärer ZRAM-Recompressionsalgorithmus. zstd

Geräteeigenschaften pro ZRAM

Wenn mmd.zram.num_devices größer als 1 ist, können bestimmte Eigenschaften optional für jedes ZRAM-Gerät konfiguriert werden. Dazu muss die Eigenschaft auf einen durch Kommas getrennten Wert mit genau mmd.zram.num_devices Elementen festgelegt werden. Zu den Eigenschaften gehören:

  • mmd.zram.size
  • mmd.zram.comp_algorithm
  • mmd.zram.device_priority
  • mmd.zram.recompression.enabled
  • mmd.zram.recompression.huge_idle.enabled
  • mmd.zram.recompression.idle.enabled
  • mmd.zram.recompression.huge.enabled
  • mmd.zram.recompression.threshold_bytes
  • mmd.zram.recompression.algorithm
  • mmd.zram.writeback.device_size
  • mmd.zram.writeback.huge_idle.enabled
  • mmd.zram.writeback.idle.enabled
  • mmd.zram.writeback.huge.enabled

Einstellung der vorhandenen ZRAM-Einrichtung

swapon_all ist zwar weiterhin in Android verfügbar, um ZRAM und festplattenbasierten Swap-Speicher einzurichten, mmd ist jedoch der bevorzugte Ansatz für die ZRAM-Verwaltung, da die Konfiguration einfacher ist und erweiterte Funktionen wie die ZRAM-Neukomprimierung unterstützt werden.

Wenn die mmd-ZRAM-Einrichtung durch mmd.zram.enabled aktiviert wird:

  • Die ZRAM-Einrichtung in der swapon_all-Implementierung wird zu einem No-Op.
  • Vorhandene ZRAM-Konfigurationen wie config_zramWriteback in der Overlay-Datei config.xml und ro.zram.*-Writeback-Systemeigenschaften werden ignoriert.

ZRAM-Wartungseinstellungen

Die ZRAM-Wartung sollte sofort funktionieren. Sie können sie jedoch mit den Systemattributen in diesem Abschnitt weiter optimieren.

ZRAM-Wartungsplanung

Mit diesen Eigenschaften wird gesteuert, wie und wann ZRAM-Wartungsaufgaben von system_server geplant werden.

Attribut Verwenden Standard
mm.zram.maintenance.first_delay_seconds Die Verzögerung, bevor die erste ZRAM-Wartung gestartet wird. 3600 (1 Stunde)
mm.zram.maintenance.periodic_delay_seconds Die Verzögerung zwischen aufeinanderfolgenden ZRAM-Wartungsplanungen. 3600 (1 Stunde)
mm.zram.maintenance.require_device_idle Gibt an, ob die ZRAM-Wartung nur initiiert werden soll, wenn das Gerät inaktiv ist. true
mm.zram.maintenance.require_battery_not_low Gibt an, ob der Akku nicht leer sein muss, bevor die ZRAM-Wartung gestartet wird. true

ZRAM-Writeback-Richtlinie

Die folgenden Parameter steuern, wann und welcher Speichertyp auf das Sicherungsgerät geschrieben wird:

Attribut Verwenden Standard
mmd.zram.writeback.backoff_seconds Die Backoff-Zeit seit dem letzten Writeback-Vorgang. 600 (10 Minuten)
mmd.zram.writeback.min_idle_seconds Wird mit mmd.zram.writeback.max_idle_seconds kombiniert, um das Alter im Leerlauf für eine Seite zu berechnen, damit sie basierend auf dem Anteil der Speichernutzung für das Zurückschreiben infrage kommt. Das berechnete Alter im Leerlauf wird exponentiell zwischen den beiden Parametern interpoliert, um den Aufwand zu minimieren, wenn der Arbeitsspeicher nicht ausgelastet ist. 72000 (20 Stunden)
mmd.zram.writeback.max_idle_seconds Maximale Anzahl an Sekunden, die für die dynamische Berechnung des Alters von inaktiven Seiten basierend auf der Arbeitsspeicherauslastung verwendet werden. 90000 (25 Stunden)
mmd.zram.writeback.huge.enabled Gibt an, ob der HUGE-Seitenrückschreibevorgang aktiviert werden soll. false
mmd.zram.writeback.idle.enabled Gibt an, ob der IDLE-Seitenrückschreibevorgang aktiviert werden soll. true
mmd.zram.writeback.huge_idle.enabled Gibt an, ob der HUGE_IDLE-Seitenrückschreibevorgang aktiviert werden soll. true
mmd.zram.writeback.min_bytes Mindestanzahl an Byte, die in einer Runde des Leerlauf-Writeback zurückgeschrieben werden müssen. 5242880 (5 MiB)
mmd.zram.writeback.max_bytes Maximale Anzahl von Byte, die in einer Runde des Leerlauf-Writeback zurückgeschrieben werden sollen. 314572800 (300 MiB)
mmd.zram.writeback.max_bytes_per_day Maximale Anzahl von Byte, die in einem Zeitraum von 24 Stunden zurückgeschrieben werden sollen. 25769803776 (24 GiB)
mmd.zram.writeback.limit.enabled Gibt an, ob das Tagesbudgetlimit für den Rückschreibevorgang berücksichtigt werden soll. true

Richtlinie für die ZRAM-Neukomprimierung

Die folgenden Parameter steuern, wann und welcher Arbeitsspeicher rekomprimiert wird:

Attribut Verwenden Standard
mmd.zram.recompression.backoff_seconds Die Backoff-Zeit seit der letzten Neukomprimierung. 1800 (30 Minuten)
mmd.zram.recompression.min_idle_seconds Wird mit mmd.zram.recompression.max_idle_seconds kombiniert, um das inaktive Alter für eine Seite zu berechnen, damit sie basierend auf dem Anteil der Arbeitsspeichernutzung für die Neukomprimierung infrage kommt. Das berechnete Alter im Leerlauf wird exponentiell zwischen den beiden Parametern interpoliert, um den Aufwand zu minimieren, wenn der Arbeitsspeicher nicht ausgelastet ist. 7200 (2 Stunden)
mmd.zram.recompression.max_idle_seconds Maximale Anzahl an Sekunden, die für die dynamische Berechnung des Alters von inaktiven Seiten verwendet werden. 14400 (4 Stunden)
mmd.zram.recompression.threshold_bytes Die Mindestgröße in Byte von ZRAM-Seiten, die für die erneute Komprimierung infrage kommen. 1024 (1 KiB)
mmd.zram.recompression.huge.enabled Gibt an, ob die HUGE-Seitenrekomprimierung aktiviert werden soll. true
mmd.zram.recompression.idle.enabled Gibt an, ob die IDLE-Seitenrekomprimierung aktiviert werden soll. true
mmd.zram.recompression.huge_idle.enabled Gibt an, ob die HUGE_IDLE-Seitenrekomprimierung aktiviert werden soll. true

ZRAM-Tracking von inaktiven Seiten

mmd Bei der ZRAM-Wartung werden ZRAM-Seiten als inaktiv markiert, je nachdem, wie lange der letzte Zugriff auf sie zurückliegt. Für diese Funktion müssen die Kernelkonfigurationen CONFIG_ZRAM_TRACK_ENTRY_ACTIME oder CONFIG_ZRAM_MEMORY_TRACKING aktiviert sein. CONFIG_ZRAM_TRACK_ENTRY_ACTIME ist in GKI-Kerneln ab Version 6.18 standardmäßig aktiviert. Bei früheren Kernels ist der Arbeitsspeicheraufwand höher und die Funktion ist nicht standardmäßig aktiviert.

Wenn die Kernelkonfiguration nicht aktiviert ist, wird für die mmd-ZRAM-Wartung eine Software-Ersatzlogik verwendet, um inaktive ZRAM-Seiten zu verfolgen:

  1. Markieren Sie alle ZRAM-Seiten als inaktiv, wenn mmd gestartet wird.

  2. Überspringe die nächsten ZRAM-Wartungen, bis die erforderliche Backoff-Periode abgelaufen ist.

  3. ZRAM-Writeback oder erneutes Komprimieren von inaktiven Seiten. Wenn aufgrund von Writeback-Beschränkungen noch inaktive Seiten vorhanden sind, schreibt mmd die Seiten bei der nächsten Wartung zurück, ohne neue Seiten als inaktiv zu markieren (Schritt 4 wird übersprungen).

  4. Wenn alle inaktiven Seiten zurückgeschrieben wurden, markieren Sie alle ZRAM-Seiten wieder als inaktiv und kehren Sie zu Schritt 2 zurück. Wenn ZRAM-Writeback deaktiviert ist, markiert mmd alle ZRAM-Seiten als inaktiv, wenn die ZRAM-Neukomprimierung nach der Dauer der Inaktivität für die Neukomprimierung erfolgt.

Anleitung zur Fehlerbehebung und Validierung

Mit den folgenden Validierungsschritten und Verfahren zur Fehlerbehebung können Sie mmd- und ZRAM-Vorgänge überprüfen und diagnostizieren.

ZRAM-Einrichtung validieren

So prüfen Sie, ob mmd ZRAM während des Bootvorgangs erfolgreich konfiguriert hat:

  1. Aktiven Komprimierungsalgorithmus und Festplattengröße prüfen:

    cat /sys/block/zram0/comp_algorithm
    cat /sys/block/zram0/disksize
    
  2. Prüfen Sie die mmd-Systemeigenschaften und den Status des ausgeführten Dienstes:

    getprop | grep mmd.zram
    dumpsys -l | grep mmd
    

ZRAM-Wartung und -Rückschreiben validieren

Prüfen Sie, ob die Wartungsaufgaben für ZRAM-Writeback und ‑Neukomprimierung funktionieren:

  1. Status des zugrunde liegenden Blockgeräts prüfen:

    cat /sys/block/zram0/bd_stat
    
  2. Prüfen Sie die Effizienz der Neukomprimierung, indem Sie /sys/block/zram0/mm_stat beobachten. Änderungen bei der Größe komprimierter Daten sollten nach Wartungszyklen sichtbar werden.

Per-Prozess-Writeback validieren

So können Sie prüfen, ob der prozessbezogene Writeback funktioniert:

  • Prüfen Sie adb logcat -s mmd auf erfolgreiche Writeback-Logs oder Fehlerdiagnosen.

Häufige Probleme und Diagnosen

Im Folgenden finden Sie einige häufige Fehlersituationen, die bei Nutzern auftreten können:

  • WritebackDailyLimitExceeded:Dieser Fehler weist darauf hin, dass das Kontingent für mmd.zram.writeback.max_bytes_per_day erreicht wurde. In diesem Fall pausiert mmd den Leerlauf-Writeback, bis das gleitende 24-Stunden-Fenster weiterläuft.
  • Process prefetch or writeback failed:Dieser Fehler kann in Logcat beobachtet werden, wenn ein ioctl fehlschlägt. Häufige Ursachen:
    • EBADF oder ESRCH: Der Zielprozess wurde beendet, bevor mmd die pidfd an den Kernel senden konnte.
    • ENOSPC: Die Partition des zugrunde liegenden Speichers ist voll oder die Warteschlange des Loop-Geräts ist leer.
  • ZRAM nicht eingerichtet:Wenn mmd ZRAM beim Booten nicht konfigurieren kann, liegt das möglicherweise daran, dass Legacy-swapon_all- oder Vendor-Init-Scripts /dev/block/zram0 gesperrt haben, bevor mmd ausgeführt werden konnte.