Önceki bölümlerde, çekirdeğin sistem genelinde belleği nasıl yönettiğini görmüştük. Bu bölümde, Android'in tek tek uygulamaların bellek kullanımını bölümlendirmek ve kontrol etmek için kullandığı mekanizma olan Bellek Kontrol Grupları (memcg) hakkında daha ayrıntılı bilgi veriyoruz.
Sistemin geri kazanma için uygulamaları hedefleyebileceği veya uygulamalara bellek sınırları koyabileceği düzey memcg olduğundan, uygulama bellek ayak izlerinin proaktif olarak yönetilmesini sağlamak için memcg'yi anlamak çok önemlidir.
Bellek kontrol grupları (memcg)
Kontrol grupları (cgroup'lar), işlemleri hiyerarşik gruplar halinde düzenlemeye ve sistem kaynaklarını (CPU, bellek ve G/Ç gibi) bunlar arasında dağıtmaya olanak tanıyan bir Linux çekirdek özelliğidir. memcg, özellikle bellek için kullanılan cgroup denetleyicisidir.
Temel memcg kavramları
- Memcg Ücreti: Bir memcg'deki bir işlem, anonim veya dosya destekli bir bellek sayfası ayırdığında bu sayfa memcg'ye "ücretlendirilir". Bir memcg'nin toplam ücreti, içindeki tüm işlemler tarafından kullanılan tüm sayfaların toplamıdır.
- Hiyerarşik Muhasebe: Bellek kullanımı ağaçta yukarı doğru hesaplanır. Bir alt kontrol grubundaki ücret, üst kontrol grubunun kullanımına da yansıtılır.
- Bellek Sınırları: Her memcg'nin, aşılması durumunda geri kazanmayı veya hatta OOM Killer'ı tetikleyen sınırları (ör.
memory.maxveyamemory.high) olabilir. Bu sınırlar, genel sistem belleğinden bağımsızdır. - Memcg başına geri kazanma: Bir memcg sınırı aştığında veya sistemin belleğe ihtiyacı olduğunda çekirdek, geri kazanma için belirli bir memcg'yi hedefleyebilir. Bu, dosya sayfalarının çıkarılması veya anonim sayfalarının ZRAM'e takas edilmesi anlamına gelir.
Android memcg hiyerarşisi
Android, uygulama işlemlerini yönetmek için belirli bir hiyerarşi kullanır. Bu yapı, sistemin farklı uygulama türlerine (ör. ön plan ve arka plan) farklı politikalar uygulamasını sağlar.

/sys/fs/cgroup/apps/: Tüm Android uygulamalarının kökü.uid_<UID>/: Her uygulamanın kullanıcı kimliği için bir dizin. Aynı uygulama paketine ait tüm işlemler bu grubu paylaşır.pid_<PID>/: Her bir işlem ve ondan ayrılan tüm alt işlemler için bir dizin. Bu sayede, birden fazla süreci olan uygulamalar için ayrıntılı kontrol ve muhasebe yapılabilir.
Uygulamalı alıştırma: memcg'yi keşfetme
Bu alıştırmada, MemoryLab için memcg dizinini bulacak ve bellek yükünü gerçek zamanlı olarak gözlemleyeceksiniz.
1. MemoryLab'i başlatma
Cihazınızda MemoryLab'in çalıştığından emin olun.
2. MemoryLab'in memcg'sini bulma
Öncelikle, çalışan MemoryLab uygulamasının PID'sini alın:
adb shell pidof com.android.memorylab
# Example output: 11672
Şimdi cgroup dizinini bulun. Bu bilgiyi /proc/<PID>/cgroup bölümünde bulabilirsiniz:
adb shell cat /proc/11672/cgroup
# Example output: 0::/apps/uid_10274/pid_11672
cgroup v2'de, 0:: karakterinden sonraki yol, /sys/fs/cgroup karakterine göre memcg hiyerarşisini gösterir. Bu nedenle tam yol /sys/fs/cgroup/apps/uid_10274/pid_11672/ olur.
3. Read memcg stats
Bu dizine gidip anahtar dosyalara bakın:
# Current memory usage (in bytes)
adb shell cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.current
# Example output:
# 1591324672
memory.current, şu anda bu cgroup'a uygulanan toplam bellek miktarını (bayt cinsinden) gösterir.
# 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 bir döküm sağlar: * anon: Anonim bellek miktarı (yığınlar, yığın izleme). * file: Dosya destekli bellek miktarı (sayfa önbelleği). *
swap: ZRAM'e takas edilen bellek miktarı.
4. Değişiklikleri gözlemleme
- MemoryLab'i açın.
memory.currentdeğerini not edin.- Java Belleği Ayır (10 MB)'a birkaç kez dokunun.
memory.currentbölümünü tekrar okuyun. Her dokunmada yaklaşık 10 MB arttığını görürsünüz.- Bit Eşlemleri Ayır'a dokunun.
anonartışını görmek içinmemory.statbölümüne bakın.
memory.reclaim ile proaktif geri alma
memcg'nin (v2) güçlü bir özelliği memory.reclaim dosyasıdır. Bu dosyaya bir değer yazıldığında çekirdek, bu memcg'den ve altındaki tüm memcg'lerden hemen o miktarda belleği geri almaya çalışır.
Android'in memory.reclaim kullanım şekli
Android'in CachedAppOptimizer özelliği, uygulamalar dondurulduktan sonra bellekten en iyi şekilde yararlanmak için bu özelliği kullanır. Android Uygulama Dondurucu, önbelleğe alınan uygulamaların çalışmadıkları sırada mümkün olduğunca az RAM tüketmesini sağlar. Bir uygulama arka plana taşınıp dondurulduğunda sistem, uygulamanın mevcut bellek kullanımını memory.reclaim dosyasına yazar. Bu işlem, çekirdeği olası tüm dosya sayfalarını çıkarmaya ve tüm anonim sayfaları ZRAM'e taşımaya zorlayarak uygulamanın yerleşik ayak izini en aza indirir.
memory.current dosyasını okuyup memory.reclaim dosyasına geri yazarak aynı "maksimum geri kazanım" değerine manuel olarak da ulaşabilirsiniz:
# 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"
Alıştırma: Geri alma ve izlemeye zorlama
Artık çekirdeği, MemoryLab'den belleği geri almaya ve etkinliği Perfetto izinde yakalamaya zorlayacağız.
- Hazırlık: MemoryLab'in bazı tahsisleri (Java ve Bitmaps) olduğundan emin olun.
İzlemeyi Başlat: Planlama, geri alma ve sayfa önbelleği etkinliklerini yakalamak için bu satır içi izleme yapılandırmasını kullanın.
# 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 } } } EOFTetikleyici Basınç ve Geri Alma:
- MemoryLab'de Allocate Native Memory (1GB) [Yerel Bellek Ayır (1 GB)] seçeneğine dokunun. Bu durum, sistem genelinde baskı oluşturur.
Ayrı bir terminalde 200 MB'ı geri alın:
adb shell "echo 200M > /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.reclaim"
Hata Geri Yükleme: MemoryLab'e geri dönün. Thrash Pagecache (Refault test) seçeneğine dokunun.
İzlemeyi Durdur: İzleme terminalinde Ctrl+C tuşlarına basın.
Perfetto'da geri kazanma analizini yapma
İzlemeyi açtığınızda hem sistem genelinde hem de uygulama başına geri kazanma işlemini görebilirsiniz:

İzde aşağıdakileri arayın:
- kswapd: Kernel iş parçacıkları altında
kswapd0simgesini arayın (yukarıdaki ekran görüntüsünde manuel olarak en üste sabitlenmiştir). Sistem boş sayfalar bulmakta zorlandığı için bu alanın uyandığını ve çalıştığını (yeşil dilimler) görürsünüz. - Doğrudan geri alma:
com.android.memorylabişlem ileti dizilerine bakın. İş parçacığının planlama izinin hemen altında mor ftrace etkinlik dilimleri (ör.mm_vmscan_direct_reclaim_begin) gösterilir. Bu, uygulamanın iş parçacığının, çekirdeğin sayfaları boşaltmasını beklerken duraklatıldığını gösterir. - RSS ve Değişim Sayaçları:
mem.rss.anon: Tahsis düğmelerine dokundukça artar.mem.swap:kswapdve uygulamanın kendi iş parçacıkları, bu anonim sayfaları ZRAM'e sıkıştırdıkça (doğrudan geri alma işlemine tabidir) kademeli olarak artar.
- memcg Reclaim: Manuel geri kazanmayı tetiklediğiniz ana yakınlaştırırsanız
rss.anonverss.filedeğerlerinde keskin bir düşüşün yanı sıramm_vmscan_memcg_reclaimetkinliklerini görürsünüz.
← Sistem genelinde | ↑ Yukarı | kswapd ve lmkd etkileşimi →