Di bagian sebelumnya, kita telah melihat cara kernel mengelola sistem memori di seluruh sistem. Dalam bab ini, kita akan membahas lebih dalam Grup Kontrol Memori (memcg), mekanisme yang digunakan Android untuk mempartisi dan mengontrol penggunaan memori untuk setiap aplikasi.
Memahami memcg sangat penting karena di sinilah sistem dapat menargetkan setiap aplikasi untuk mengklaim kembali atau menetapkan batas memori, sehingga memungkinkan pengelolaan jejak memori aplikasi secara proaktif.
Grup kontrol memori (memcg)
Grup Kontrol (cgroup) adalah fitur kernel Linux yang memungkinkan proses diatur ke dalam grup hierarkis dan mendistribusikan resource sistem (seperti CPU, memori, dan I/O) di antara grup tersebut. memcg adalah pengontrol cgroup khusus untuk memori.
Konsep utama memcg
- Memcg Charge: Saat proses dalam memcg mengalokasikan halaman memori (anonim atau yang didukung file), halaman tersebut akan "dikenai biaya" ke memcg. Total biaya memcg adalah jumlah semua halaman yang digunakan oleh semua proses di dalamnya.
- Akuntansi Hierarkis: Penggunaan memori dihitung hingga ke atas hierarki. Biaya dalam cgroup turunan juga dihitung terhadap penggunaan induknya.
- Batas Memori: Setiap memcg dapat memiliki batas (seperti
memory.maxataumemory.high) yang memicu klaim kembali atau bahkan OOM killer jika terlampaui, terlepas dari memori sistem global. - Klaim Kembali Per-memcg: Saat memcg melebihi batasnya, atau saat sistem memerlukan memori, kernel dapat menargetkan memcg tertentu untuk klaim kembali. Artinya, mengeluarkan halaman filenya atau menukar halaman anonimnya ke ZRAM.
Hierarki memcg Android
Android menggunakan hierarki tertentu untuk mengelola proses aplikasi. Struktur ini memungkinkan sistem menerapkan kebijakan yang berbeda ke berbagai jenis aplikasi (misalnya, latar depan vs. latar belakang).

/sys/fs/cgroup/apps/: Root untuk semua aplikasi Android.uid_<UID>/: Direktori untuk setiap ID Pengguna aplikasi. Semua proses yang termasuk dalam paket aplikasi yang sama berbagi grup ini.pid_<PID>/: Direktori untuk setiap proses individual dan turunan yang di- fork darinya. Hal ini memungkinkan kontrol dan akuntansi yang terperinci untuk aplikasi dengan beberapa proses.
Latihan interaktif: menjelajahi memcg
Dalam latihan ini, Anda akan menemukan direktori memcg untuk MemoryLab dan mengamati biaya memorinya secara real-time.
1. Meluncurkan MemoryLab
Pastikan MemoryLab berjalan di perangkat Anda.
2. Menemukan memcg MemoryLab
Pertama, dapatkan PID aplikasi MemoryLab yang sedang berjalan:
adb shell pidof com.android.memorylab
# Example output: 11672
Sekarang, temukan direktori cgroup-nya. Anda dapat menemukannya di /proc/<PID>/cgroup:
adb shell cat /proc/11672/cgroup
# Example output: 0::/apps/uid_10274/pid_11672
Di cgroup v2, jalur setelah 0:: mewakili hierarki memcg relatif terhadap /sys/fs/cgroup. Jadi, jalur lengkapnya adalah /sys/fs/cgroup/apps/uid_10274/pid_11672/.
3. Membaca statistik memcg
Buka direktori tersebut dan lihat file kunci:
# Current memory usage (in bytes)
adb shell cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.current
# Example output:
# 1591324672
memory.current menampilkan total jumlah memori (dalam byte) yang saat ini dikenai biaya ke cgroup ini.
# 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 memberikan perincian: * anon: Jumlah memori anonim
(heap, stack). * file: Jumlah memori yang didukung file (cache halaman). *
swap: Jumlah memori yang ditukar ke ZRAM.
4. Mengamati perubahan
- Buka MemoryLab.
- Perhatikan nilai
memory.current. - Ketuk Allocate Java Memory (10MB) beberapa kali.
- Baca
memory.currentlagi. Anda akan melihatnya bertambah sekitar 10 MB untuk setiap ketukan. - Ketuk Allocate Bitmaps. Periksa
memory.statuntuk melihat peningkatananon.
Klaim kembali proaktif dengan memory.reclaim
Fitur memcg (v2) yang canggih adalah file memory.reclaim. Menulis nilai ke file ini akan menginstruksikan kernel untuk segera mencoba mengklaim kembali jumlah memori tersebut dari memcg ini dan memcg apa pun di bawahnya.
Cara Android menggunakan memory.reclaim
CachedAppOptimizer Android menggunakan fitur ini untuk mengklaim kembali memori secara maksimal dari aplikasi setelah dibekukan. App Freezer Android memastikan aplikasi yang di-cache menggunakan RAM sesedikit mungkin saat tidak berjalan. Saat aplikasi berpindah ke latar belakang dan dibekukan, sistem akan menulis penggunaan memori aplikasi saat ini ke dalam file memory.reclaim. Hal ini memaksa kernel untuk mengeluarkan semua halaman file yang memungkinkan dan menukar semua halaman anonim ke ZRAM, sehingga meminimalkan jejak residen aplikasi.
Anda dapat mencapai "klaim kembali maksimal" yang sama secara manual dengan membaca memory.current dan menuliskannya kembali ke memory.reclaim:
# 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"
Latihan: memaksa klaim kembali dan pelacakan
Sekarang kita akan memaksa kernel untuk mengklaim kembali memori dari MemoryLab dan merekam aktivitas dalam rekaman aktivitas Perfetto.
- Persiapan: Pastikan MemoryLab memiliki beberapa alokasi (Java dan Bitmap).
Mulai Pelacakan: Gunakan konfigurasi pelacakan inline ini untuk merekam peristiwa penjadwalan, klaim kembali, dan cache halaman.
# 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 } } } EOFMemicu Tekanan dan Klaim Kembali:
- Di MemoryLab, ketuk Allocate Native Memory (1GB). Tindakan ini akan memicu tekanan di seluruh sistem.
Di terminal terpisah, klaim kembali 200 MB:
adb shell "echo 200M > /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.reclaim"
Kesalahan Kembali: Beralih kembali ke MemoryLab. Ketuk Thrash Pagecache (Refault test).
Hentikan Pelacakan: Tekan Ctrl+C di terminal pelacakan.
Menganalisis klaim kembali di Perfetto
Saat membuka rekaman aktivitas, Anda dapat melihat klaim kembali di seluruh sistem dan per aplikasi:

Cari hal berikut dalam rekaman aktivitas:
- kswapd: Cari
kswapd0di bagian Kernel threads (dalam screenshot di atas, item ini disematkan secara manual di bagian atas). Anda akan melihatnya aktif dan berjalan (irisan hijau) saat sistem berupaya menemukan halaman kosong. - Klaim Kembali Langsung: Lihat thread proses
com.android.memorylab. Anda akan melihat irisan peristiwa ftrace berwarna ungu (sepertimm_vmscan_direct_reclaim_begin) yang muncul langsung di bawah jalur penjadwalan thread. Hal ini menunjukkan bahwa thread aplikasi itu sendiri terhenti menunggu kernel mengosongkan halaman. - Penghitung RSS dan Swap:
mem.rss.anon: Meningkat saat Anda mengetuk tombol alokasi.mem.swap: Meningkat secara stabil saatkswapddan thread aplikasi sendiri (yang tunduk pada klaim kembali langsung) mengompresi halaman anonim tersebut ke ZRAM.
- Klaim Kembali memcg: Jika memperbesar momen saat Anda memicu klaim kembali manual, Anda akan melihat penurunan tajam pada
rss.anondanrss.file, disertai dengan peristiwamm_vmscan_memcg_reclaim.
← Seluruh sistem | ↑ Atas | Interaksi kswapd dan lmkd →