In den vorherigen Abschnitten haben wir gesehen, wie der Kernel den Arbeitsspeicher systemweit verwaltet. In diesem Kapitel gehen wir näher auf Memory Control Groups (memcg) ein. Das ist der Mechanismus , mit dem Android die Arbeitsspeichernutzung für einzelne Apps partitioniert und steuert.
Es ist wichtig, memcg zu verstehen, da das System auf dieser Ebene einzelne Apps für die Freigabe von Arbeitsspeicher ansprechen oder Arbeitsspeicherlimits für sie festlegen kann. So lässt sich die Arbeitsspeichernutzung von Apps proaktiv verwalten.
Memory Control Groups (memcg)
Control Groups (cgroups) sind eine Linux-Kernel-Funktion, mit der Prozesse in hierarchische Gruppen organisiert und Systemressourcen wie CPU, Arbeitsspeicher und E/A auf sie verteilt werden können. memcg ist der cgroup-Controller speziell für den Arbeitsspeicher.
Wichtige memcg-Konzepte
- Memcg-Belastung: Wenn ein Prozess in einer memcg eine Arbeitsspeicherseite zuweist (entweder anonym oder dateibasiert), wird diese Seite der memcg in Rechnung gestellt. Die Gesamtbelastung einer memcg ist die Summe aller Seiten, die von allen Prozessen darin verwendet werden.
- Hierarchische Abrechnung: Die Arbeitsspeichernutzung wird in der Hierarchie nach oben abgerechnet. Eine Belastung in einer untergeordneten cgroup wird auch auf die Nutzung der übergeordneten cgroup angerechnet.
- Arbeitsspeicherlimits: Jede memcg kann Limits haben (z. B.
memory.maxodermemory.high), die unabhängig vom globalen Arbeitsspeicher des Systems die Freigabe von Arbeitsspeicher oder sogar den OOM-Killer auslösen, wenn sie überschritten werden. - Freigabe von Arbeitss/peicher pro memcg: Wenn eine memcg ihr Limit überschreitet oder das System Arbeitsspeicher benötigt, kann der Kernel eine bestimmte memcg für die Freigabe von Arbeitsspeicher ansprechen. Das bedeutet, dass die Dateiseiten entfernt oder die anonymen Seiten in ZRAM ausgelagert werden.
Die Android-memcg-Hierarchie
Android verwendet eine bestimmte Hierarchie, um App-Prozesse zu verwalten. Diese Struktur ermöglicht es dem System, verschiedene Richtlinien auf verschiedene Arten von Apps anzuwenden (z. B. im Vordergrund oder im Hintergrund).

/sys/fs/cgroup/apps/: Das Stammverzeichnis für alle Android-Anwendungen.uid_<UID>/: Ein Verzeichnis für die Nutzer-ID jeder App. Alle Prozesse, die zum selben App-Paket gehören, verwenden diese Gruppe.pid_<PID>/: Ein Verzeichnis für jeden einzelnen Prozess und alle untergeordneten Prozesse, die daraus abgeleitet wurden. Dies ermöglicht eine präzise Steuerung und Abrechnung für Apps mit mehreren Prozessen.
Praktische Übung: memcg untersuchen
In dieser Übung suchen Sie das memcg-Verzeichnis für MemoryLab und beobachten die Arbeitsspeicherbelastung in Echtzeit.
1. MemoryLab starten
Achten Sie darauf, dass MemoryLab auf Ihrem Gerät ausgeführt wird.
2. Memcg von MemoryLab suchen
Rufen Sie zuerst die PID der ausgeführten MemoryLab-App ab:
adb shell pidof com.android.memorylab
# Example output: 11672
Suchen Sie jetzt das cgroup-Verzeichnis. Sie finden es unter /proc/<PID>/cgroup:
adb shell cat /proc/11672/cgroup
# Example output: 0::/apps/uid_10274/pid_11672
In cgroup v2 stellt der Pfad nach 0:: die memcg-Hierarchie relativ zu /sys/fs/cgroup dar. Der vollständige Pfad ist also /sys/fs/cgroup/apps/uid_10274/pid_11672/.
3. Memcg-Statistiken lesen
Wechseln Sie in dieses Verzeichnis und sehen Sie sich die wichtigsten Dateien an:
# Current memory usage (in bytes)
adb shell cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.current
# Example output:
# 1591324672
memory.current zeigt die Gesamtmenge des Arbeitsspeichers (in Byte) an, die derzeit dieser cgroup in Rechnung gestellt wird.
# Detailed statistics
adb shell cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.stat | head -n 10
# Example output:
# anon 1585098752
# file 741376
# kernel 5484544
# kernel_stack 393216
# pagetables 4583424
# sec_pagetables 0
# percpu 216
# sock 0
# vmalloc 4096
# shmem 20480
memory.stat enthält eine Aufschlüsselung: * anon: Menge des anonymen Arbeitsspeichers
(Heaps, Stacks). * file: Menge des dateibasierten Arbeitsspeichers (Seitencache). *
swap: Menge des Arbeitsspeichers, der in ZRAM ausgelagert wurde.
4. Änderungen beobachten
- Öffnen Sie MemoryLab.
- Notieren Sie sich den Wert von
memory.current. - Tippen Sie mehrmals auf Allocate Java Memory (10MB).
- Lesen Sie
memory.currentnoch einmal. Der Wert sollte mit jedem Tippen um etwa 10 MB steigen. - Tippen Sie auf Allocate Bitmaps. Prüfen Sie, ob
anoninmemory.statgestiegen ist.
Proaktive Freigabe von Arbeitsspeicher mit memory.reclaim
Eine leistungsstarke Funktion von memcg (v2) ist die Datei memory.reclaim. Wenn Sie einen Wert in diese Datei schreiben, wird der Kernel angewiesen, sofort zu versuchen, diese Menge an Arbeitsspeicher aus dieser memcg und allen darunter liegenden memcgs freizugeben.
So verwendet Android memory.reclaim
Der CachedAppOptimizer von Android verwendet diese Funktion, um nach dem Einfrieren von Apps möglichst viel Arbeitsspeicher freizugeben. Der App Freezer von Android sorgt dafür, dass im Cache gespeicherte Apps so wenig RAM wie möglich verbrauchen, wenn sie nicht ausgeführt werden. Wenn eine App in den Hintergrund verschoben und eingefroren wird, schreibt das System die aktuelle Arbeitsspeichernutzung der App in die Datei memory.reclaim. Dadurch wird der Kernel gezwungen, alle möglichen Dateiseiten zu entfernen und alle anonymen Seiten in ZRAM auszulagern. So wird die Arbeitsspeichernutzung der App minimiert.
Sie können dieselbe „maximale Freigabe“ manuell erreichen, indem Sie memory.current lesen und wieder in memory.reclaim schreiben:
# Force reclaim of everything
adb shell "cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.current > /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.reclaim"
Übung: Freigabe von Arbeitsspeicher erzwingen und Ablauf verfolgen
Wir zwingen den Kernel jetzt, Arbeitsspeicher von MemoryLab freizugeben, und erfassen die Aktivität in einem Perfetto-Trace.
- Vorbereiten: Achten Sie darauf, dass MemoryLab einige Zuweisungen hat (Java und Bitmaps).
Tracing starten: Verwenden Sie diese Inline-Trace-Konfiguration, um Ereignisse zur Planung, Freigabe von Arbeitsspeicher und zum Seitencache zu erfassen.
# Use a config that captures scheduling, reclaim and page cache events adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/reclaim.perfetto-trace <<EOF buffers: { size_kb: 131072 fill_policy: RING_BUFFER } data_sources: { config { name: "linux.ftrace" ftrace_config { ftrace_events: "sched/sched_switch" ftrace_events: "sched/sched_wakeup" ftrace_events: "kmem/rss_stat" ftrace_events: "mm_filemap_add_to_page_cache" ftrace_events: "mm_filemap_delete_from_page_cache" ftrace_events: "vmscan/mm_vmscan_direct_reclaim_begin" ftrace_events: "vmscan/mm_vmscan_direct_reclaim_end" ftrace_events: "vmscan/mm_vmscan_memcg_reclaim_begin" ftrace_events: "vmscan/mm_vmscan_memcg_reclaim_end" symbolize_ksyms: true } } } data_sources: { config { name: "linux.process_stats" process_stats_config { scan_all_processes_on_start: true } } } EOFDruck und Freigabe von Arbeitsspeicher auslösen:
- Tippen Sie in MemoryLab auf Allocate Native Memory (1GB). Dadurch wird systemweiter Druck ausgelöst.
Geben Sie in einem separaten Terminal 200 MB frei:
adb shell "echo 200M > /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.reclaim"
Fehler zurückgeben: Wechseln Sie zurück zu MemoryLab. Tippen Sie auf Thrash Pagecache (Refault test).
Trace beenden: Drücken Sie im Trace-Terminal Strg + C.
Freigabe von Arbeitsspeicher in Perfetto analysieren
Wenn Sie den Trace öffnen, sehen Sie sowohl die systemweite als auch die app-spezifische Freigabe von Arbeitsspeicher:

Suchen Sie im Trace nach Folgendem:
- kswapd: Suchen Sie unter Kernel threads nach
kswapd0(im Screenshot oben wurde es manuell oben angepinnt). Sie sehen, dass es aktiviert und ausgeführt wird (grüne Abschnitte), während das System versucht, kostenlose Seiten zu finden. - Direkte Freigabe von Arbeitsspeicher: Sehen Sie sich die Threads des
com.android.memorylabProzesses an. Direkt unter dem Planungs-Track des Threads werden violette ftrace-Ereignisabschnitte wiemm_vmscan_direct_reclaim_beginangezeigt. Das bedeutet, dass der App-Thread selbst angehalten wird und darauf wartet, dass der Kernel Seiten freigibt. - RSS- und Auslagerungszähler:
mem.rss.anon: Steigt, wenn Sie auf die Zuweisungsschaltflächen tippen.mem.swap: Steigt stetig, dakswapdund die eigenen Threads der App (die der direkten Freigabe von Arbeitsspeicher unterliegen) diese anonymen Seiten in ZRAM komprimieren.
- Memcg-Freigabe von Arbeitsspeicher: Wenn Sie auf den Moment zoomen, in dem Sie die manuelle
Freigabe von Arbeitsspeicher ausgelöst haben, sehen Sie einen starken Rückgang bei
rss.anonundrss.file, begleitet vonmm_vmscan_memcg_reclaim-Ereignissen.
← Systemweit | ↑ Nach oben | Interaktion von kswapd und lmkd →