Alat penilaian cepat

Saat Anda perlu menyelidiki penggunaan memori, mulailah dengan alat penilaian tingkat tinggi untuk mengidentifikasi kategori memori yang paling signifikan.

dumpsys meminfo

Cara paling umum untuk mendapatkan ringkasan penggunaan memori aplikasi adalah dumpsys meminfo. Untuk melihat perincian mendetail termasuk semua pemetaan memori, sebaiknya sertakan flag -a:

adb shell dumpsys meminfo -a <package_name_or_pid>

Berikut adalah contoh output dari aplikasi yang mengalami tekanan memori (perhatikan SwapPss yang tinggi):

** MEMINFO in pid 4562 [com.android.memorylab] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
  Native Heap      394      268       64    17440     4264    29416    18128     8040
  Dalvik Heap      165        8        0      672     8196    40949    32757     8192
 Dalvik Other       47       28        0      604     1132
        Stack      112      108        4      312      120
...
        TOTAL    33197      580      788    21920   167776    70365    50885    16232

 App Summary
                       Pss(KB)                        Rss(KB)
                        ------                         ------
           Java Heap:       12                          32608
         Native Heap:      268                           4264
                Code:      724                         125672
               Stack:      108                            120
            Graphics:        0                              0
       Private Other:      256
              System:    31829
             Unknown:                                    5112

           TOTAL PSS:    33197            TOTAL RSS:   167776       TOTAL SWAP PSS:    21920

 Objects
               Views:       15         ViewRootImpl:        1
         AppContexts:        5           Activities:        1
...

Menafsirkan data

  • Pss Total: Proportional Set Size. Ini adalah jumlah Private Dirty
    • Private Clean + bagian memori yang adil dari proses Anda yang dibagikan ke proses lain (seperti boot image Zygote). Ini adalah metrik terbaik untuk "seberapa banyak memori yang digunakan aplikasi ini".
  • Private Dirty: Ini adalah RAM yang hanya digunakan oleh proses Anda dan telah dimodifikasi (atau merupakan memori anonim). Ini adalah angka paling penting untuk menemukan kebocoran karena memori ini tidak dapat dihapus.
  • Private Clean: RAM yang hanya digunakan oleh proses Anda, tetapi merupakan salinan file yang tidak dimodifikasi di penyimpanan (seperti file DEX). Aplikasi dapat dihentikan oleh OS jika memori hampir habis.
  • SwapPss: Memori yang telah dikompresi dan di-swap ke ZRAM. Hal ini dapat terjadi karena sistem mengalami tekanan memori atau karena Android Runtime telah mengidentifikasi proses latar belakang yang akan dipadatkan (memindahkan halaman yang tidak digunakan atau tidak aktif ke ZRAM). Dalam contoh dumpsys, hampir semua Native Heap dan Dalvik Heap telah dipindahkan ke ZRAM.
  • Ringkasan Aplikasi: Kategorisasi tingkat lebih tinggi yang menggabungkan baris mendetail ke dalam bucket yang dapat dipahami.
  • Objek: Berguna untuk melacak instance Activities dan ViewRootImpl yang bocor. Jika Anda keluar dari aplikasi dan memaksa GC, jumlah Activities akan kembali ke 0.

Bagian anggaran memori

Di Android 18 dan yang lebih tinggi, dumpsys meminfo juga mencetak bagian Memory Budget saat membuang satu aplikasi. Bagian ini membaca statistik memcg dari proses dan seluruh aplikasi (paket), sehingga Anda tidak perlu menemukan file cgroup sendiri. Berikut adalah bagian dari aplikasi contoh MemoryLab di latar depan, setelah tiga ketukan Allocate Java Memory (10MB):

 Memory Budget
                        Process(KB)       Package(KB)
                        -----------       -----------
  Current Usage:              83820             87976
  Limit:                       none           4718592
  Limit Source:                none     MemoryLimiter
  Peak Usage:                 85136             89292
  Swap Used:                      0                 0

  Usage Breakdown
    Anonymous:                81700             81700
    File:                        96              4200
    File Mapped:                 16               616
    Shared Memory:               16                16
    Kernel:                    1580              1632
    Page Tables:                640               640
    Slab:                       439               458

  Pressure & Reclaim
    Throttle Events:              0                 0
    Refaults (Anon):              0                 0
    Refaults (File):              0                 0
  • Penggunaan Saat Ini: Memori yang dibebankan ke memcg (memory.current). Ini adalah angka yang dibatasi oleh anggaran memori. Dalam contoh, jumlahnya meningkat sekitar 36.700 KB setelah tiga alokasi Java 10 MB, sejalan dengan TOTAL PSS. Total paket lebih tinggi daripada total proses, bahkan untuk aplikasi proses tunggal saat halaman file yang di-cache dari operasi sebelumnya belum diklaim kembali.
  • Limit: Batas klaim kembali (memory.high) yang berlaku saat ini, atau none jika tidak ada. Dalam contoh, paket memiliki batas memori sistem dan prosesnya tidak memiliki batasnya sendiri.
  • Sumber Batas: Sumber batas. AndroidManifest adalah <memory-budget> yang dideklarasikan dalam manifes aplikasi, MemoryBudgetManager adalah anggaran yang ditetapkan aplikasi pada waktu proses, MemoryLimiter adalah batas memori sistem, dan am memory-limiter adalah penggantian manual yang ditetapkan dengan adb.
  • Penggunaan Puncak: Tagihan tertinggi sejak memcg dibuat (memory.peak). Ini menunjukkan N/A pada kernel yang tidak mendukungnya.
  • Swap Digunakan: Memori yang dikompresi ke ZRAM (memory.swap.current).
  • Perincian Penggunaan: Kolom utama memory.stat, seperti memori anonim dan yang didukung file.
  • Tekanan & Klaim Kembali: Peristiwa Throttle menghitung berapa kali memcg melampaui batas memory.high-nya. Refault menghitung halaman yang ditukar atau dikeluarkan, lalu diperlukan lagi. Jika angka ini meningkat saat Anda menggunakan aplikasi, batasnya lebih ketat daripada set kerja aplikasi.

Dengan flag -a atau -v, bagian ini juga mencantumkan setiap penghitung mentah dari memory.stat dan memory.events.

Latihan praktik: triase cepat dengan meminfo

Latihan ini menunjukkan cara berbagai jenis alokasi muncul di meminfo.

  1. Luncurkan aplikasi:

    adb shell am start -W -n com.android.memorylab/.MainActivity
    
  2. Memeriksa memori dasar pengukuran:

    adb shell dumpsys meminfo -s com.android.memorylab
    

    (Flag -s memberikan ringkasan singkat dan padat tentang kategori memori).

  3. Alokasikan Memori Java: Ketuk tombol Alokasikan Memori Java (10 MB) 3 kali di aplikasi.

  4. Amati perubahannya: Jalankan meminfo -s lagi. Anda akan melihat nilai Java Heap meningkat sekitar 30.000 KB (30 MB).

  5. Allocate Native Memory: Ketuk tombol Allocate Native Memory (1GB Incompressible) sekali.

  6. Amati perubahannya: Jalankan meminfo -s lagi. Nilai Native Heap seharusnya sekarang menunjukkan peningkatan yang sangat besar (~1.000.000 KB).

  7. Bandingkan dengan memcg (Android 18 dan yang lebih baru): Lihat bagian Memory Budget di akhir output meminfo -s. Penggunaan Saat Ini bertambah seiring dengan TOTAL PSS setelah setiap alokasi, karena alokasi Java dan native ditagih ke memcg aplikasi.

Tampilan global

Untuk melihat penggunaan memori di seluruh sistem, jalankan:

adb shell dumpsys meminfo

Perintah ini memberikan ringkasan penggunaan RAM, termasuk total RAM, RAM kosong, dan daftar proses yang diurutkan berdasarkan PSS.

Metrik sistem utama

  • ZRAM: Swap terkompresi di RAM.
  • DMA-BUF: Buffer memori bersama dan grafis. Versi Android modern menggunakan DMA-BUF secara ekstensif untuk rendering UI. Jika total DMA-BUF sangat tinggi, selidiki proses yang menggunakan banyak grafis menggunakan /sys/kernel/debug/dma_buf/bufinfo.
  • RAM yang hilang: Memori yang tidak diperhitungkan oleh kernel atau proses apa pun (misalnya, region yang dicadangkan hardware).

Statistik memcg

Setiap proses aplikasi memiliki grup kontrol memori (memcg) sendiri, dan kernel terus menjalankan total memori yang dibebankan kepadanya (lihat memcg untuk mengetahui perbedaan penghitungan ini dari RSS dan PSS). Membaca file ini tidak memerlukan banyak biaya dan tidak mengganggu aplikasi, sehingga Anda dapat mengambil sampelnya setiap detik saat menjalankan alur pengguna.

Cari jalur memcg proses dari baris 0:: dari /proc/<PID>/cgroup, bukan membuat jalur sendiri, karena tata letak cgroup dapat berbeda di antara perangkat. Teruskan setiap perintah perangkat ke adb shell sebagai string yang dikutip tunggal sehingga shell perangkat melihat tanda kutip:

PID=$(adb shell pidof -s <package_name>)

CG=/sys/fs/cgroup$(adb shell "sed -n 's/^0:://p' /proc/$PID/cgroup")

adb shell "cat $CG/memory.current $CG/memory.swap.current"

adb shell "grep -E '^(anon|file|workingset_refault_.*) ' $CG/memory.stat"

File kuncinya adalah:

  • memory.current: Memori yang dibebankan ke proses, dalam byte. Ini adalah angka yang dibatasi oleh anggaran memori.
  • memory.swap.current: Memori yang dikompresi ke ZRAM, dalam byte.
  • memory.stat: Perincian biaya, dalam byte untuk ukuran. anon adalah memori anonim, seperti heap Java dan native. file adalah cache halaman yang didukung file, seperti kode dan resource. workingset_refault_anon dan workingset_refault_file menghitung halaman yang ditukar atau dikeluarkan, lalu diperlukan lagi. Jumlah refault yang meningkat berarti proses tersebut kekurangan memori.
  • memory.events: Jumlah peristiwa batas memori. high menghitung berapa kali proses dibatasi karena melebihi batas memory.high.

Direktori induk memcg proses adalah milik seluruh aplikasi (UID-nya). Filenya mencakup memori semua proses aplikasi yang berjalan, ditambah halaman file yang di-cache yang tersisa dari proses aplikasi sebelumnya yang telah keluar dan belum diklaim kembali:

adb shell "cat $CG/../memory.current"

Jika Anda mendapatkan error izin, jalankan adb root dan coba lagi. Beberapa perangkat hanya memungkinkan Anda membaca file ini sebagai root.

Untuk panduan terpandu tentang file ini dengan aplikasi contoh MemoryLab, lihat Latihan praktik: menjelajahi memcg.

showmap

Untuk perincian yang jauh lebih mendetail tentang pemetaan memori proses, gunakan showmap. Alat ini membaca dari /proc/<pid>/smaps.

adb shell showmap <pid>

showmap mencantumkan setiap peta memori dalam proses. Pemetaan kunci yang perlu diperhatikan antara lain:

  • [anon:scudo:primary] atau [anon:libc_malloc]: Heap native. Versi Android modern menggunakan alokator Scudo.
  • *.art: Image heap Java (misalnya, boot image).
  • [anon:dalvik-main space]: Heap Java utama.
  • *.so: Pustaka bersama.
  • *.{oat,dex,odex,vdex}: Kode DEX yang dikompilasi.

Anda dapat mengurutkan output untuk menemukan konsumen memori pribadi terbesar:

# Sort by private clean + private dirty memory
adb shell showmap <pid> | awk '{print $6+$7, $0}' | sort -rn | head -n 10

Contoh output:

 virtual                     shared   shared  private  private                   Anon      Shmem     File      Shared   Private
    size      RSS      PSS    clean    dirty    clean    dirty     swap  swapPSS HugePages PmdMapped PmdMapped Hugetlb  Hugetlb    Locked    # object
-------- -------- -------- -------- -------- -------- -------- -------- -------- --------- --------- --------- -------- -------- -------- ---- ------------------------------
2776    18176     5784     2823        0     3008      308     2468     4700     4700         0         0         0        0        0        0   47 [anon:scudo:primary]
560      952      876      657      316        0      560        0       12       12         0         0         0        0        0        0    8 /data/app/.../base.apk
448   393216      448      448        0        0        0      448        0        0         0         0         0        0        0        0    2 [anon:dalvik-main space]
...

Latihan praktik: pembahasan mendalam dengan showmap

Pelajari cara mengidentifikasi pemetaan memori tertentu dan membedakan antara memori bersih dan kotor.

  1. Mmap Clean Memory: Ketuk tombol Mmap Clean Anon Memory (10MB) di aplikasi MemoryLab sekali.
  2. Mendapatkan ID Proses: UI aplikasi menampilkan PID-nya. Anda juga dapat menemukannya dengan perintah ini:

    adb shell pidof com.android.memorylab
    
  3. Memeriksa dengan showmap:

    # Replace <PID> with the actual process ID from the previous step
    adb shell showmap <PID> | grep "memorylab-clean"
    
  4. Identifikasi pemetaan: Anda akan melihat pemetaan anonim berlabel [anon:memorylab-clean] dengan ukuran virtual tepat 10.240 KB. Perhatikan bahwa nilai private dirty untuk peta ini kemungkinan adalah 0. Ini adalah memori anonim "bersih" karena kita menggunakan mmap untuk mencadangkan ruang virtual, tetapi belum menulis ke dalamnya (sehingga tidak ada RAM fisik yang benar-benar digunakan).

  5. Perbandingan Heap Native: Bandingkan ini dengan pemetaan [anon:scudo:primary] yang akan muncul di showmap jika Anda menjalankannya setelah langkah 5 latihan meminfo. Karena alokasi native 1 GB tersebut sebenarnya menulis ke setiap halaman, halaman tersebut "dirty" dan akan muncul secara signifikan di kolom private dirty.

  6. Tips Pro (Objek Besar): Perhatikan alokasi Java Heap dari latihan meminfo. Karena merupakan array byte 10 MB, array tersebut kemungkinan muncul di showmap sebagai [anon:dalvik-free list large object space]. Android Runtime (ART) menempatkan objek yang lebih besar dari 12 KB ke dalam Large Object Space (LOS) terpisah untuk menghindari fragmentasi di heap utama.

procstats

Meskipun meminfo memberikan snapshot pada suatu waktu, procstats memberikan data historis dengan mengambil sampel status dan penggunaan memori secara berkala dari semua aplikasi yang berjalan. Ini adalah alat utama yang digunakan untuk pemantauan kesehatan memori jangka panjang dan yang mendorong pelaporan penggunaan memori di Setelan Android.

# View stats for the last 3 hours
adb shell dumpsys procstats --hours 3

Memahami status

Output procstats bisa sangat banyak. Bagian yang paling penting adalah metrik dalam tanda kurung di samping setiap status proses:

Top: 100% (54MB-64MB-67MB / 49MB-58MB-61MB / 110MB-120MB-130MB over 4)

Formatnya adalah: (% waktu dalam status) (minPss-avgPss-maxPss / minUss-avgUss-maxUss / minRss-avgRss-maxRss di atas sampel)

  • Pss (Proportional Set Size): Memori bersama dibagi secara proporsional di antara proses.
  • Uss (Unique Set Size): Memori yang hanya digunakan oleh proses ini (setara dengan Private Clean + Private Dirty).
  • Rss (Resident Set Size): Total memori fisik yang digunakan, termasuk semua halaman bersama (cenderung dihitung berlebihan).

Mengapa hal ini penting:

  • Aplikasi Stabil: min/rata-rata/maks berdekatan.
  • Kebocoran Memori: nilai maksimum jauh lebih tinggi daripada nilai minimum, dan nilai rata-rata meningkat seiring waktu seiring bertambahnya jumlah sampel.
  • Penggunaan yang Berfluktuasi: nilai maksimum jauh lebih tinggi daripada rata-rata, yang menunjukkan operasi berat sementara (seperti pemrosesan gambar) yang dapat menyebabkan OOM jika terjadi pada waktu yang salah.

Status proses

procstats melacak aplikasi di beberapa negara bagian (sering kali disingkat):

  • Persist: Proses sistem penting yang selalu berjalan.
  • Atas: Aplikasi saat ini berada di latar depan dan terlihat oleh pengguna.
  • ImpFg (Latar Depan Penting): Proses latar belakang penting (seperti IME) atau aplikasi dengan layanan latar depan.
  • ImpBg (Latar Belakang Penting): Proses latar belakang yang dianggap penting bagi sistem.
  • Fgs / BFgs: Layanan Latar Depan atau Layanan Latar Depan Terikat.
  • Service / ServRst: Layanan latar belakang atau layanan yang sedang dimulai ulang.
  • Cached / LastAct: Aplikasi yang di-cache di latar belakang untuk memulai ulang dengan cepat. Proses ini aman untuk dihentikan oleh sistem.

Status memori perangkat dan statistik waktu proses

procstats juga melacak berapa lama seluruh perangkat mengalami tekanan memori. Cari bagian Run time Stats:

Run time Stats:
  SOff/Norm: +1h10m15s
   SOn/Norm: +15m20s
        Low: +2m10s
       Crit: +45s
  • SOff / SOn: Layar Nonaktif vs. Layar Aktif.
  • Norm / Mod / Low / Crit: Tingkat tekanan memori (Normal, Moderate, Low, Critical).

Jika perangkat menghabiskan banyak waktu dalam status Low atau Crit, perangkat akan terasa lambat karena kernel secara agresif mengklaim kembali memori dan Low Memory Killer (LMK) mulai menghentikan proses latar belakang. Kemudian, Anda dapat melihat statistik per paket untuk mengetahui aplikasi mana yang memiliki penggunaan memori tinggi, khususnya saat perangkat berada dalam status tertekan ini.


← Konsep | ↑ Atas | Java →