Hızlı değerlendirme araçları

Bellek kullanımını incelemeniz gerektiğinde, en önemli bellek kategorilerini belirlemek için üst düzey değerlendirme araçlarıyla başlayın.

dumpsys meminfo

Bir uygulamanın bellek kullanımına genel bakış elde etmenin en yaygın yolu dumpsys meminfo yöntemidir. Tüm bellek eşlemelerini içeren ayrıntılı bir döküm görmek için -a işaretini eklemek genellikle yararlı olur:

adb shell dumpsys meminfo -a <package_name_or_pid>

Aşağıda, bellek baskısı altındaki bir uygulamanın örnek çıkışı verilmiştir (yüksek SwapPss değerine dikkat edin):

** 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
...

Verileri yorumlama

  • Pss Total: Orantılı küme boyutu. Bu, Private Dirty + Private Clean ile işleminizin diğer işlemlerle (Zygote başlatma görüntüsü gibi) paylaşılan adil bellek payının toplamıdır. Bu, "bu uygulamanın sorumlu olduğu bellek miktarı" için en iyi metriktir.
  • Özel Kirli: Bu, yalnızca işleminizin kullandığı ve değiştirilmiş (veya anonim bellek olan) RAM'dir. Bu bellek bırakılamadığı için sızıntıları bulma konusunda en önemli sayıdır.
  • Özel Temiz: Yalnızca işleminiz tarafından kullanılan ancak depolama alanındaki bir dosyanın (DEX dosyası gibi) değiştirilmemiş kopyası olan RAM. Bellek azsa işletim sistemi tarafından bırakılabilir.
  • SwapPss: Sıkıştırılmış ve ZRAM'e aktarılmış bellek. Bu durum, sistemde bellek baskısı olduğunda veya Android Çalışma Zamanı, sıkıştırılacak arka plan işlemleri (kullanılmayan veya etkin olmayan sayfalarını ZRAM'e taşıma) belirlediğinde ortaya çıkabilir. dumpsys örneğinde, Native Heap ve Dalvik Heap'nin neredeyse tamamı ZRAM'e taşınmıştır.

  • Önemli nokta: "Uygulama Özeti" bölümündeki Java Yığını ve Yerel Yığın değerleri, yerleşik (fiziksel) belleği temsil eder. Bir uygulamanın belleği ZRAM'e sıkıştırılmışsa bu özel özet değerleri beklenenden çok daha düşük görünebilir. Tam resmi görmek için her zaman TOTAL SWAP PSS veya ayrıntılı SwapPss sütununu kontrol edin.

  • Uygulama Özeti: Ayrıntılı satırları anlaşılır gruplar halinde birleştiren daha üst düzey bir kategorizasyon.

  • Nesneler: Sızdırılan Activities ve ViewRootImpl örneklerini izlemek için kullanışlıdır. Uygulamanızdan çıkıp GC'yi zorlarsanız Activities sayısı 0'a döner.

Bellek bütçesi bölümü

Android 18 ve sonraki sürümlerde dumpsys meminfo, tek bir uygulamayı döküme aldığında Bellek Bütçesi bölümünü de yazdırır. Bu bölüm, işlemin ve uygulamanın tamamının (paketin) memcg istatistiklerini okur. Bu sayede cgroup dosyalarını kendiniz bulmanız gerekmez. Allocate Java Memory (10MB) (Java Belleği Ayır (10 MB)) düğmesine üç kez dokunduktan sonra MemoryLab örnek uygulamasının ön plandaki bölümü şu şekilde görünür:

 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
  • Mevcut Kullanım: Memcg'ye (memory.current) yüklenen bellek. Bu, bellek bütçelerinin sınırladığı sayıdır. Örnekte, üç adet 10 MB Java tahsisinden sonra yaklaşık 36.700 KB artarak TOTAL PSS ile uyumlu hale geldi. Daha önceki bir çalıştırmadan kalan önbelleğe alınmış dosya sayfaları henüz geri alınmadığında, tek işlemli bir uygulama için bile paket toplamı işlem toplamından daha yüksek olur.
  • Sınır: Şu anda geçerli olan geri alma eşiği (memory.high) veya eşik yoksa none. Örnekte, paketin sistem belleği sınırı var ve işlemin kendi sınırı yok.
  • Sınır Kaynağı: Sınırın nereden geldiği. AndroidManifest, uygulama manifestinde beyan edilen bir <memory-budget>, MemoryBudgetManager, uygulamanın çalışma zamanında ayarladığı bir bütçe, MemoryLimiter, sistem bellek sınırı ve am memory-limiter, adb ile ayarlanan manuel geçersiz kılmadır.
  • En Yüksek Kullanım: memcg oluşturulduğundan beri en yüksek ücret (memory.peak). Bu, desteklemeyen çekirdeklerde N/A değerini gösterir.
  • Kullanılan Swap: ZRAM'e sıkıştırılmış bellek (memory.swap.current).
  • Kullanım dökümü: Anonim ve dosya destekli bellek gibi memory.stat ana alanları.
  • Baskı ve Geri Kazanma: Kısıtlama Etkinlikleri, memcg'nin memory.high sınırını kaç kez aştığını sayar. Refaults, takas edilen veya çıkarılan ve daha sonra tekrar ihtiyaç duyulan sayfaları sayar. Uygulamayı kullanırken bu sayılar artıyorsa sınır, uygulamanın çalışma grubundan daha dardır.

-a veya -v işaretiyle bu bölümde memory.stat ve memory.events'deki her ham sayaç da listelenir.

Uygulama alıştırması: meminfo ile hızlı önceliklendirme

Bu alıştırmada, farklı tahsis türlerinin meminfo içinde nasıl gösterildiği açıklanmaktadır.

  1. Uygulamayı başlatma:

    adb shell am start -W -n com.android.memorylab/.MainActivity
    
  2. Referans bellek kullanımını kontrol etme:

    adb shell dumpsys meminfo -s com.android.memorylab
    

    (-s işareti, bellek kategorilerinin kısa ve öz bir özetini sağlar).

  3. Java Belleği Ayırma: Uygulamada Java Belleği Ayır (10 MB) düğmesine 3 kez dokunun.

  4. Değişikliği gözlemleyin: meminfo -s komutunu tekrar çalıştırın. Java Yığın değerinin yaklaşık 30.000 KB (30 MB) arttığını görürsünüz.

  5. Yerel Bellek Ayırma: Yerel Bellek Ayır (1 GB Sıkıştırılamaz) düğmesine bir kez dokunun.

  6. Değişikliği gözlemleyin: meminfo -s komutunu tekrar çalıştırın. Yerel Yığın değeri artık büyük bir artış (~1.000.000 KB) göstermelidir.

  7. memcg ile karşılaştırma (Android 18 ve sonraki sürümler): meminfo -s çıkışının sonundaki Bellek Bütçesi bölümüne bakın. Hem Java hem de yerel ayırmalar uygulamanın memcg'sine yüklendiğinden, her ayırmadan sonra TOTAL PSS ile birlikte Current Usage da artar.

Genel görünüm

Sistem genelinde bellek kullanımını görmek için şu komutu çalıştırın:

adb shell dumpsys meminfo

Bu komut; toplam RAM, boş RAM ve PSS'ye göre sıralanmış işlemlerin listesi dahil olmak üzere RAM kullanımının özetini gösterir.

Temel sistem metrikleri

  • ZRAM: RAM'deki sıkıştırılmış takas.
  • DMA-BUF: Grafikler ve paylaşılan bellek arabellekleri. Modern Android sürümleri, kullanıcı arayüzü oluşturma için DMA-BUF'u yoğun bir şekilde kullanır. DMA-BUF toplamı çok yüksekse /sys/kernel/debug/dma_buf/bufinfo kullanarak grafik ağırlıklı işlemleri inceleyin.
  • Kayıp RAM: Çekirdek veya herhangi bir işlem tarafından hesaba katılmayan bellek (ör. donanıma ayrılmış bölgeler).

memcg istatistikleri

Her uygulama işleminin kendi bellek kontrol grubu (memcg) vardır ve çekirdek, bu gruba yüklenen belleğin toplamını tutar (bu hesaplamanın RSS ve PSS'den nasıl farklı olduğunu öğrenmek için memcg bölümüne bakın). Bu dosyaları okumak kolaydır ve uygulamanızı rahatsız etmez. Bu nedenle, kullanıcı işlemleri akışını çalıştırırken her saniye örnekleyebilirsiniz.

Cgroup düzeni cihazlar arasında farklılık gösterebileceğinden, yolu kendiniz oluşturmak yerine /proc/<PID>/cgroup dosyasının 0:: satırından bir işlemin memcg yolunu bulun. Cihaz kabuğunun tırnak işaretlerini görmesi için her cihaz komutunu adb shell'ya tek tırnak içine alınmış dize olarak iletin:

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"

Önemli dosyalar şunlardır:

  • memory.current: İşleme ayrılan bellek (bayt cinsinden). Bellek bütçelerinin sınırladığı sayı budur.
  • memory.swap.current: ZRAM'e sıkıştırılmış bellek (bayt cinsinden).
  • memory.stat: Ücretin dökümü (boyutlar bayt cinsinden gösterilir). anon, Java ve yerel yığınlar gibi anonim bellektir. file, kod ve kaynaklar gibi dosya destekli sayfa önbelleğidir. workingset_refault_anon ve workingset_refault_file, takas edilen veya çıkarılan ve daha sonra tekrar ihtiyaç duyulan sayfaları sayar. Yeniden hata sayılarının artması, işlemin belleğinin yetersiz olduğu anlamına gelir.
  • memory.events: Bellek sınırı etkinliklerinin sayısı. high, işlemin memory.high sınırını aştığı için kaç kez kısıtlandığını sayar.

İşlem memcg'sinin ana dizini, uygulamanın tamamına (UID'sine) aittir. Dosyaları, uygulamanın çalışan tüm işlemlerinin belleğini ve uygulamanın çıkış yapmış ve henüz geri alınmamış önceki işlemlerinden kalan önbelleğe alınmış dosya sayfalarını içerir:

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

İzin hatası alırsanız adb root komutunu çalıştırıp tekrar deneyin. Bazı cihazlar bu dosyaları yalnızca root olarak okumanıza izin verir.

MemoryLab örnek uygulamasıyla bu dosyaların rehberli bir açıklaması için Uygulamalı alıştırma: memcg'yi keşfetme başlıklı makaleyi inceleyin.

showmap

Bir işlemin bellek eşlemelerinin çok daha ayrıntılı dökümü için showmap komutunu kullanın. Bu araç, /proc/<pid>/smaps kaynağından okuma yapar.

adb shell showmap <pid>

showmap, işlemdeki her bellek eşlemesini listeler. Aranacak önemli eşlemeler şunlardır:

  • [anon:scudo:primary] veya [anon:libc_malloc]: Yerel yığın. Modern Android sürümleri Scudo ayırıcıyı kullanır.
  • *.art: Java yığın görüntüleri (ör. başlatma görüntüsü).
  • [anon:dalvik-main space]: Ana Java yığını.
  • *.so: Paylaşılan kitaplıklar.
  • *.{oat,dex,odex,vdex}: Derlenmiş DEX kodu.

En büyük özel bellek tüketicilerini bulmak için çıkışı sıralayabilirsiniz:

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

Örnek çıkış:

 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]
...

Uygulama alıştırması: showmap ile ayrıntılı inceleme

Belirli bellek eşlemelerini nasıl tanımlayacağınızı ve temiz ile kirli bellek arasındaki farkı nasıl ayırt edeceğinizi öğrenin.

  1. Mmap Temiz Bellek: MemoryLab uygulamasında Mmap Temiz Anonim Bellek (10 MB) düğmesine bir kez dokunun.
  2. İşlem kimliğini alma: Uygulamanın kullanıcı arayüzünde işlem kimliği gösterilir. Bu komutla da bulabilirsiniz:

    adb shell pidof com.android.memorylab
    
  3. Showmap ile inceleme:

    # Replace <PID> with the actual process ID from the previous step
    adb shell showmap <PID> | grep "memorylab-clean"
    
  4. Eşlemeyi tanımlayın: Tam olarak 10.240 KB sanal boyuta sahip [anon:memorylab-clean] etiketli anonim bir eşleme görürsünüz. Bu eşlemenin özel kirli değerinin büyük olasılıkla 0 olduğunu unutmayın. Sanal alanı ayırmak için mmap kullandığımız ancak henüz bu alana yazmadığımız için bu, "temiz" anonim bellektir (bu nedenle fiziksel RAM tüketilmez).

  5. Yerel Yığın Karşılaştırması: Bunu, meminfo alıştırmasının 5. adımından sonra çalıştırdığınızda showmap içinde görünecek olan [anon:scudo:primary] eşlemeleriyle karşılaştırın. Bu 1 GB'lık yerel ayırma aslında her sayfaya yazdığı için bu sayfalar "kirli"dir ve özel kirli sütununda yoğun bir şekilde görünür.

  6. Uzman ipucu (Büyük Nesneler): meminfo alıştırmasındaki Java Yığını ayırmalarına dikkat edin. 10 MB'lık bayt dizileri oldukları için showmap içinde [anon:dalvik-free list large object space] olarak görünebilirler. Android Çalışma Zamanı (ART), ana yığında parçalanmayı önlemek için 12 KB'tan büyük nesneleri ayrı bir Büyük Nesne Alanı'na (LOS) yerleştirir.

procstats

meminfo, belirli bir zamandaki durumu gösterirken procstats, çalışan tüm uygulamaların durumunu ve bellek kullanımını düzenli olarak örnekleyerek geçmiş verileri sağlar. Bu, uzun süreli bellek sağlığını izlemek için kullanılan birincil araçtır ve Android ayarlarındaki bellek kullanımı raporlamasını yönlendirir.

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

Durumları anlama

procstats çıktısı çok fazla olabilir. En önemli kısım, her işlem durumunun yanındaki parantez içindeki metriklerdir:

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

Biçim şu şekildedir: (% time in state) (minPss-avgPss-maxPss / minUss-avgUss-maxUss / minRss-avgRss-maxRss over samples)

  • Pss (Orantılı Küme Boyutu): Paylaşılan bellek, işlemler arasında orantılı olarak bölünür.
  • Uss (Unique Set Size): Yalnızca bu işlem tarafından kullanılan bellek (Private Clean + Private Dirty'ye eşdeğer).
  • Rss (Yerleşik Küme Boyutu): Tüm paylaşılan sayfalar dahil olmak üzere kullanılan toplam fiziksel bellek (fazla sayma eğilimindedir).

Bu neden önemli?

  • Kararlı uygulama: Minimum, ortalama ve maksimum değerler birbirine yakındır.
  • Bellek Sızıntısı: Maksimum değer, minimum değerden önemli ölçüde yüksektir ve örnek sayısı arttıkça ortalama değer zaman içinde yükselir.
  • Dalgalı Kullanım: Maksimum değer, ortalama değerden çok daha yüksektir. Bu durum, yanlış zamanda gerçekleşirse OOM'lere neden olabilecek geçici ağır işlemleri (ör. görüntü işleme) gösterir.

İşlem durumları

procstats, uygulamaları çeşitli durumlarda (genellikle kısaltılmış olarak) izler:

  • Kalıcı: Her zaman çalışan kritik sistem işlemleri.
  • Üst: Uygulama şu anda ön plandadır ve kullanıcı tarafından görülebilir.
  • ImpFg (Önemli Ön Plan): Kritik arka plan işlemleri (ör. IME'ler) veya ön plan hizmeti olan uygulamalar.
  • ImpBg (Önemli Arka Plan): Sistem için önemli olduğu düşünülen arka plan işlemleri.
  • Fgs / BFgs: Ön plan hizmetleri veya bağlı ön plan hizmetleri.
  • Service / ServRst: Arka plan hizmetleri veya şu anda yeniden başlatılan hizmetler.
  • Önbelleğe alınmış / LastAct: Hızlı yeniden başlatma için arka planda önbelleğe alınan uygulamalar. Sistemin bunları sonlandırması güvenlidir.

Cihaz bellek durumu ve çalışma süresi istatistikleri

procstats, cihazın tamamının bellek baskısı altında ne kadar süre kaldığını da izler. Çalışma süresi istatistikleri bölümünü bulun:

Run time Stats:
  SOff/Norm: +1h10m15s
   SOn/Norm: +15m20s
        Low: +2m10s
       Crit: +45s
  • SOff / SOn: Ekran kapalı ve ekran açık.
  • Norm / Mod / Low / Crit: Bellek baskısı seviyeleri (Normal, Orta, Düşük, Kritik).

Bir cihaz Düşük veya Kritik durumlarda önemli ölçüde zaman harcıyorsa çekirdek, belleği agresif bir şekilde geri aldığından ve Low Memory Killer (LMK) arka plan işlemlerini sonlandırmaya başladığından cihaz yavaş çalışır. Ardından, cihaz bu stresli durumlardayken özellikle hangi uygulamaların yüksek bellek kullanımına sahip olduğunu görmek için paket başına istatistikleri inceleyebilirsiniz.


← Kavramlar | ↑ Yukarı | Java →