Sistem belleği bütçeleri

Android 17 ve sonraki sürümlerde platform, genel uygulama bellek sınırlayıcı ile birlikte çalışan iki tamamlayıcı Linux cgroup v2 mekanizmasını kullanarak sistem işlemi belleğini yönetir:

  • Sistem arka plan programı koruma tabanları (SystemMemoryBudgetManager, memory.min ile): Kendi kendini ayarlayan cgroup v2 memory.min ayırmaları (her arka plan programının yerleşik yerleşik çalışma grubunun %90'ına ayarlanır ve toplam fiziksel RAM'in% 10'u ile sınırlıdır), bellek baskısı altında kritik etkileşimli arka plan programlarını ve kabuk işlemlerini (system_server, surfaceflinger, grafik composer HAL, audioserver, cameraserver, netd, SystemUI ve ana ekran başlatıcı) korur. Bu sayede statik PinnerService mlock dosya sabitleme işlemi değiştirilir.
  • Sistem uygulaması bellek tavanları (memory.high ile <memory-budget>): Kalıcı ve arka plan sistem uygulamaları (Bluetooth, Nfc, CalendarProvider, Traceur, MediaProvider, :PhotoPicker, NetworkStack, AppSearch ve TeleService) için manifest dosyalarında beyan edilen iş yüküne göre ayarlanmış cgroup v2 memory.high esnek sınırları (genellikle 30 MB ila 190 MB), genel bellek baskısı oluşmadan önce soğuk dosya sayfası önbelleğini ve patlama sonrası anonim yığını proaktif olarak geri alır.

Aşağıdaki tabloda iki mekanizma karşılaştırılmaktadır:

Boyut Sistem arka plan programı koruma katları Sistem uygulaması bellek üst sınırları
Platform hizmeti SystemMemoryBudgetManager MemoryLimiter
Cgroup v2 kontrolü memory.min sert koruma tabanı memory.high yumuşak geri alma tavanı
Hedef süreçler Gecikme açısından kritik etkileşimli daemon'lar ve kabuk kullanıcı arayüzü (system_server, surfaceflinger, composer HAL, audioserver, cameraserver, netd, SystemUI ve Home uygulaması) Kalıcı ve başsız sistem uygulamaları, içerik sağlayıcılar ve arka plan hizmetleri (ör. Bluetooth, Nfc, MediaProvider, NetworkStack, AppSearch ve TeleService)
Boyutlandırma modeli Çalışma zamanında kendi kendine ayarlama (yerleşik çalışma grubunun% 90'ı, toplam RAM'in% 10'u ile genel olarak sınırlıdır) ve cihaz başına sıfır ayarlama tablosu RAM katmanı, işlem durumu ve ekran piksel sayısına göre kalibre edilmiş açıklayıcı <memory-budget> manifest XML özellikleri
Temel avantaj Statik PinnerService mlock dosya listelerini değiştirirken bellek baskısı altında etkileşimli kullanıcı arayüzü takılmalarını ve uyanma duraklamalarını önler. Ön plandaki ve önbelleğe alınmış uygulamalar için daha fazla fiziksel RAM bırakmak amacıyla soğuk tek seferlik dosya önbelleğini ve patlama sonrası yığını sürekli olarak çıkarır.

<memory-budget> söz dizimi, XML özellikleri, çalışma zamanı API'leri ve OS bellek kaydı hakkında daha fazla bilgi için Uygulama bellek bütçelerini ayarlama ve Android belleğini anlama ve sorunlarını giderme başlıklı makaleleri inceleyin.

SystemMemoryBudgetManager ile kritik etkileşimli daemon'ları koruma

SystemMemoryBudgetManager, bellek baskısı sırasında doğrudan kullanıcının etkileşimli yolunda bulunan işlemleri fiziksel RAM'de tutar. mlock ile APK, ODEX ve VDEX dosyalarının statik bir listesini belleğe sabitlemek yerine (PinnerService'nin config_defaultPinnerServiceFiles ve config_pinnerHomePinBytes için yaptığı gibi), SystemMemoryBudgetManager aşağıdaki işlemlere dinamik cgroup v2 memory.min katmanları atar:

  • Çekirdek sistem dilimi (/sys/fs/cgroup/system): system_server, surfaceflinger, grafik composer HAL, audioserver, cameraserver ve netd ile birlikte config_systemMemoryBudgetAdditionalSystemProcesses içinde listelenen, form faktörüne özgü yerel sistem veya tedarikçi arka plan programları (ör. XR cihazlarda android.hardware.perceptionhost ve auracamerahal).
  • Etkileşimli uygulama dilimi (/sys/fs/cgroup/apps): Yapılandırılmış SystemUI paketinin (config_systemUi) ana işlemi ve mevcut kullanıcının ana sayfa rolü sahibinin ana işlemi.

config_systemUi ile birlikte Ana Sayfa rolü sahibini korumak, tüm form faktörlerinde kapsam sağlar. config_systemUi'nin hafif bir uyumluluk paketi olduğu form faktörlerinde (ör. kadran, bildirimler ve kutuların Home uygulamasında çalıştığı Wear OS) kullanıcıya yönelik kabuk, tam çalışma seti koruması almaya devam eder. Home intent'i config_systemUi paketine çözümlenirse işlem bir kez korunur. Yalnızca her paketin ana işlemi (processName == packageName) koruma tabanı alır. Bu nedenle, yardımcı alt işlemler (ör. :screenshot) koruma bütçesini tüketmez.

Kendi kendini ayarlayan politika ve üç seviyeli cgroup yetkilendirmesi

Etkileşimli bir arka plan programının çalışma grubu, form faktörlerine ve RAM kapasitelerine göre büyük farklılıklar gösterdiğinden (ör. SystemUI, akıllı saatte yaklaşık 45 MB, 6 GB'lık bir telefonda 60 MB ve 16 GB'lık bir telefonda 180 MB kullanır) cihaz başına statik arama tabloları hassastır. Bunun yerine, SystemMemoryBudgetManager, üç sabit kullanarak her işlemin kendi yerleşik ayak izinden doğrudan tabanlar türetir:

Politika parametresi Varsayılan değer Davranış
İşlem başına taban fiyat Eşlenmemiş dosya önbelleği hariç, kapatılan memory.current tutarının% 90'ı Anonim yığın, slab ve sıcak eşlenmiş kodu korurken en soğuk% 10'luk kısmı geri kazanılabilir olarak bırakır. Böylece gerçekten soğuk sayfalar yine de çıkarılabilir. Eşlenmemiş dosya önbelleği (memory.stat üzerinden max(0, file - shmem - file_mapped)), %90 oranı uygulanmadan önce çıkarılır. Böylece, önyükleme paketi tarama önbelleği veya tek seferlik öğe okumaları alt sınırları artırmaz.
Global RAM sınırı Toplam RAM'in% 10'u (config_systemMemoryBudgetLowKb) PinnerService config_pinnerMaxPinnedMemoryPercentage önlemine uyuyor. %90'lık tabanların toplamı MemTotal değerinin% 10'unu aşarsa her taban aynı çarpanla orantılı olarak ölçeklendirilir.
Yenileme sıklığı Başlangıçtan 1, 4, 16 ve 64 saniye sonra, ardından her 30 dakikada bir Geometrik bir yerleşim serisi, her cihaz için ısınma gecikmelerini sabit kodlamadan her bir arka plan programının başlangıç sonrası çalışma grubuna yakınsar ve 30 dakikalık sabit durum yenilemesi, cihazın kullanım ömrü boyunca çalışma grubunun kademeli olarak büyümesini ve küçülmesini izler.

Linux cgroup v2 bellek denetleyicisinde (mm/memcontrol.c:effective_protection), bir yaprak cgroup'un etkin memory.min koruması, üst ve ata cgroup'larında yapılandırılan memory.min ile sınırlıdır. uid_<uid>/memory.min, 0 iken memory.min politikasını yalnızca bir yaprak pid_<pid> dizininde ayarlamak, sıfır etkili korumayla sonuçlanır. Bunun aksine, yalnızca en üstteki /sys/fs/cgroup/system diliminde sabit bir memory.min ayarlamak, talep edilmeyen korumayı tüm alt UID'lere ve işlemlere orantılı olarak dağıtır (memory_recursiveprot). Bu durumda, uid_1000 (android.uid.system) paylaşan teşhis veya ikincil işlemler, surfaceflinger ve audioserver'dan korumayı azaltabilir.

Tam arka plan programı düzeyinde izolasyon sağlamak için SystemMemoryBudgetManager, her yenilemede cgroup v2 hiyerarşisinin üç düzeyinde de koruma yazar. Bu durum Şekil 1'de gösterilmiştir:

  1. Yaprak işlem düğümü (pid_<pid>/memory.min): İşlemin (ölçeklendirilmiş) %90 çalışma kümesi tabanına ayarlanır.
  2. UID düğümü (uid_<uid>/memory.min): Yönetilen pid_* yaprak katmanlarının tam toplamına ayarlanır. Böylece, bu UID'yi paylaşan yönetilmeyen işlemler (diğer AID_SYSTEM arka plan programları veya sharedUserId="android.uid.system" paketleri gibi) memory.min = 0 olur ve koruma talep edemez.
  3. Üst düzey dilim (/sys/fs/cgroup/system/memory.min ve /sys/fs/cgroup/apps/memory.min): uid_* alt öğelerinin tam toplamına ayarlanır. Yönetilen düğümlerdeki tüm eski memory.low değerleri 0 olarak temizlenir ve önceki bir yenilemede yönetilen tüm uid_* dizinleri (ör. kullanıcı başlatıcıları değiştirdikten sonra önceki ana sayfa başlatıcısı) 0 olarak sıfırlanır.

/sys/fs/cgroup/system ve /sys/fs/cgroup/apps genelinde üç seviyeli cgroup v2 memory.min koruma hiyerarşisi. Bu hiyerarşide, yaprak işlem tabanları UID ve dilim düğümlerine toplanırken korumasız kardeş işlemler sıfırda kalır.

Şekil 1. Cgroup dilimleri arasında üç düzeyli koruma tabanı yetkilendirmesi.

MGLRU çekirdeklerinde neden memory.low yerine memory.min kullanılır?

Çok Nesilli LRU (MGLRU, Android 6.6 ve daha yeni çekirdeklerdeki varsayılan sayfa geri alma motoru) kapsamında, memory.low ve memory.min, mm/vmscan.c:shrink_one içinde farklı davranır:

  • memory.low (tek geçişli erteleme): Kullanımı memory.low değerinin altında olan bir cgroup, memcg LRU'nun (MEMCG_LRU_TAIL) sonuna döndürülür ve tek bir geri alma geçişi için atlanır. Sürekli bellek baskısı altında bir sonraki geçişte çekirdek, cgroup'u tamamen geri alır ve bir MEMCG_LOW etkinliği kaydeder. Fiziksel cihaz stres testlerinde, anonim bir bellek canavarının fiziksel RAM'in% 85'ine kadar büyümesiyle memory.low, akıllı saatte SystemUI'in yaklaşık 45 MB'tan yaklaşık 5-10 MB'a düşmesini ve 16 GB'lık katlanabilir cihazda audioserver'nin yaklaşık 14 MB'lık bir tabana karşı 15 MB'tan 2 MB'a düşmesini sağladı.
  • memory.min (kesin koruma tabanı): Kullanımı memory.min değerinin altında olan bir cgroup, genel geri alma tarafından atlanır. Şekil 2'de gösterildiği gibi, aynı% 85 RAM baskısı iş yükü altında memory.min, her bir arka plan programının yalnızca en soğuk% 10'luk kısmını atar ve SystemUI, surfaceflinger ve audioserver'yi% 90'lık tabanlarında tutar. Bu sırada sıfır anonim yeniden hata oluşur ve lmkd işlem sonlandırmalarında artış olmaz.

memory.min, yerini aldığı PinnerService mlock sabitleme korumasına uygun, fiziksel bir rezervasyon sağlar. Bu sayede, hangi etkin kod, yığın ve grafik sayfalarının kalıcı olacağını statik bir dosya listesi yerine çekirdek LRU seçer.

Sistem belleği baskısı fiziksel RAM'in% 40'ından% 95'ine yükselirken arka plan programı yerleşik belleğinin karşılaştırması. memory.min% 90'lık tabanında kalırken memory.low tek bir MGLRU erteleme geçişinden sonra çöker.

Şekil 2. Bellek baskısı arttığında arka plan işlemi çalışma kümesinin saklanması.

Başlatma öncesi ön ısıtma ve başlatma sonrası eşlenmemiş dosya önbelleğini geri alma

config_defaultPinnerServiceFiles adlı kalıcı mlock öğesinin PinnerService ile değiştirilmesi için iki başlatma zamanı davranışının koordine edilmesi gerekir:

  • Tek seferlik arka planda başlatma ön ısıtması (PinnerService): Sayfa önbelleğini ısıtmadan PinnerService mlock işlemini atlamak, SystemUI başlatıldığında (OnBootPhase_550) yaklaşık 95 MB'lık SystemUI APK, ODEX ve VDEX disk okumalarını eşzamanlı başlatma yoluna kaydırarak başlatma işleminin tamamlanmasına 300 ila 450 ms ekler. Çekirdekteki force_page_cache_ra, tek bir MADV_WILLNEED çağrısını bir önceden okuma penceresine (genellikle 128 KB ila 2 MB) sıkıştırdığı için madvise(MADV_WILLNEED) çağrısı yeterli değildir. Bunun yerine, SystemMemoryBudgetManager.shouldSkipDefaultSystemPinning etkin olduğunda PinnerService, onStart sırasında arka plan iş parçacığında config_defaultPinnerServiceFiles içindeki her dosyayı eşler, dosyayı Os.mlock ile sayfa önbelleğine eşzamanlı olarak doldurur ve hemen Os.munlock, munmap ve close'yi çağırır. Bu sayede, hızlı başlatma zamanlaması korunurken sıfır bayt kalıcı olarak kilitlenir. Böylece, sıfırdan başlatma sayfaları daha sonra kaldırılabilir.
  • system_server önyükleme paketi tarama önbelleğini hariç tutma ve geri alma: Önyükleme sırasında PackageManagerService, yüklü APK'ları tarar ve system_server cgroup'tan 1,5 ila 2,5 GB'lık soğuk eşlenmemiş dosya sayfası önbelleği bırakır. system_server için memory.min hesaplamasına dahil edilirse bu soğuk başlatma önbelleği, %10'luk global RAM sınırını doldurur ve surfaceflinger, SystemUI ve audioserver için koruma tabanlarını orantılı olarak azaltır. Sınır yetersizliğini önlemek için SystemMemoryBudgetManager, system_server için memory.stat değerini okur, eşlenmemiş dosya önbelleğini max(0, file - shmem - file_mapped) olarak hesaplar ve Şekil 3'te gösterildiği gibi% 90 alt sınırını hesaplamadan önce bu eşlenmemiş önbelleği memory.current değerinden çıkarır. Ayrıca PHASE_BOOT_COMPLETED işleminden 10 saniye sonra yönetici, Linux 6.2 ve daha yeni çekirdeklerde system_server öğesinin memory.reclaim düğümüne <unmapped_file> swappiness=0 öğesini tek seferde yazar. Bu sayede, anonim yığınları değiştirmeden veya eşlenmiş DEX ve kod sayfalarını çıkarmadan soğuk paket tarama önbelleğini proaktif olarak çıkarır. swappiness=0'yi EINVAL ile reddeden eski çekirdeklerde (ör. android14-6.1) yönetici, başlatma sırasında anonim yığını değiştirecek niteliksiz bir geri alma yazma işlemine geri dönmek yerine memory.reclaim yazma işlemini atlar.

Başlatma işleminden sonra system_server belleğinin zaman çizelgesi. Bu çizelgede 1, 4, 16 ve 64 saniyede geometrik yerleşme yenilemeleri, eşlenmemiş başlatma paketi tarama önbelleğinin% 90 memory.min tabanından hariç tutulması ve swappiness=0 ile tek seferlik memory.reclaim gösterilmektedir.

Şekil 3. Başlatma işleminden sonra koruma tabanı yakınsaması ve önbellek geri kazanımı.

Çekirdek gereksinimleri ve cihaz yapılandırma yer paylaşımları

SystemMemoryBudgetManager, memory.min değerini iç içe yerleştirilmiş cgroup'lara yaymak için Linux çekirdeğindeki mem_cgroup_calculate_protection özelliğini kullanır. Android ortak çekirdekleri android15-6.6 ve android16-6.12, tam MGLRU iç içe yerleştirilmiş koruma desteği sunar. MGLRU etkinleştirilmiş android14-6.1 çalıştıran cihazlar, mm/vmscan.c ve mm/memcontrol.c içinde üç yukarı akış geri bağlantısı gerektirir. Böylece boş ara dilim ve UID cgroup'ları, korumayı yaprak işlem cgroup'larına yayar:

  • 30d77b7eef01 (mm/mglru: fix ineffective protection calculation)
  • 8aa420617918 (mm/mglru: respect min_ttl_ms with memcgs)
  • adb8213014b2 (mm: memcg: fix stale protection of reclaim target memcg)

OEM'ler, aşağıdaki çerçeve kaynak yer paylaşımlarını kullanarak SystemMemoryBudgetManager özelliğini özelleştirebilir veya devre dışı bırakabilir:

  • config_systemMemoryBudgetLowKb (tam sayı, KB): 0 (varsayılan), tüm memory.min alt sınırlarının toplamını toplam fiziksel RAM'in% 10'u ile sınırlandırır. Pozitif bir değer, KB cinsinden açık bir sınır belirler ve negatif bir değer, cihazda SystemMemoryBudgetManager özelliğini devre dışı bırakır (eski PinnerService statik mlock sabitlemeyi korur).
  • config_systemMemoryBudgetHighKb (tam sayı, KB): 0 (varsayılan), /sys/fs/cgroup/system/memory.high değerini max olarak bırakır. Pozitif bir değer, üst dilim memory.high tavanını belirler (taban sınırından büyük veya ona eşit olmalıdır).
  • config_systemMemoryBudgetAdditionalSystemProcesses (dize dizisi): Varsayılan altı sistem arka plan işlemine ek olarak% 90 memory.min tabanlarıyla korunacak, /sys/fs/cgroup/system içinde ek gecikme açısından kritik yerel sistem veya tedarikçi arka plan işlemi adlarını (/proc/<pid>/comm ile veya 10000 altındaki sistem ve tedarikçi UID'leri için /proc/<pid>/cmdline içindeki argv[0] temel adıyla eşleştirilir) listeler. init.rc içinde memory.min değerini ayarlamak yerine bu yer paylaşımını kullanın. Çünkü SystemMemoryBudgetManager, uid_<uid>/memory.min değerini yönetilen yaprak işlemlerinin toplamı olarak yeniden hesaplar ve her yenilemede yönetilmeyen uid_* düğümlerini temizler. Örneğin, bir XR cihazı, aşağıdaki yer paylaşımlı dosya ile uzamsal izleme ve kamera HAL daemon'larını koruyabilir:

    <string-array translatable="false" name="config_systemMemoryBudgetAdditionalSystemProcesses">
        <item>android.hardware.perceptionhost</item>
        <item>auracamerahal</item>
    </string-array>
    
  • config_systemUi (dize): Platform SystemUI uygulamasının paket adı, MATCH_SYSTEM_ONLY ile çözümlenir.

Cihazdaki etkin SystemMemoryBudgetManager katmanlarını ve cgroup düğümlerini incelemek için şu komutu çalıştırın:

# Inspect policy state, resolved PIDs, and applied floors in dumpsys meminfo
adb shell dumpsys meminfo | sed -n '/System Memory Budgets/,$p'
# Inspect raw cgroup v2 memory.min nodes across the system and apps slices
adb shell head -n 1 \
  /sys/fs/cgroup/system/memory.min \
  /sys/fs/cgroup/system/uid_*/memory.min \
  /sys/fs/cgroup/system/uid_*/pid_*/memory.min \
  /sys/fs/cgroup/apps/memory.min \
  /sys/fs/cgroup/apps/uid_*/memory.min \
  /sys/fs/cgroup/apps/uid_*/pid_*/memory.min

Bellek bütçeleriyle kalıcı ve arka plan sistem uygulamalarını bağlama

SystemMemoryBudgetManager, memory.min tabanlarını kullanarak etkileşimli daemon'ları geri alınmaya karşı korur. Diğer birçok sistem uygulaması ve ayrıcalıklı platform hizmeti ise arka planda uzun süre PERSISTENT işlemleri, bağlı ön plan hizmetleri veya sık sorgulanan içerik sağlayıcılar olarak çalışır. Açık bellek tavanları olmadan bu işlemler, çok gigabaytlık Bellek Sınırlayıcı sınırlarına (ör. görünür uygulamalar için 4 GB ila 10 GB ve arka plan uygulamaları için 2 GB ila 5 GB) ulaşana veya genel bellek baskısı sistem genelinde kswapd ve düşük bellek sonlandırıcı (lmkd) etkinliğini tetikleyene kadar kısıtlanmaz.

Kısıtlanmadığında, arka plan sistem işlemleri genellikle etkin çalışma gruplarının parçası olmayan büyük miktarda soğuk bellek biriktirir:

  • Sınırsız dosya sayfası önbelleği: Medya dizine ekleyen, veritabanlarında arama yapan veya takvim ve sağlayıcı tablolarını senkronize eden hizmetler (ör. AppSearch, MediaProvider ve CalendarProvider), diskteki büyük dosyaları eşler veya bu dosyalar üzerinden akış gerçekleştirir. cgroup memory.high üst sınırı olmadan, tek seferlik okumalardan elde edilen temiz dosya destekli sayfalar, süresiz olarak işlem cgroup'una yüklenir ve yüzlerce megabayt fiziksel RAM tüketir.
  • Patlama sonrası anonim yığın saklama: Bluetooth Ses ve BLE keşif patlamaları, NetworkStack giriş portalı TLS doğrulaması veya arka plana geçiş yapan kullanıcı arayüzü yardımcıları gibi geçici etkinlik artışları yaşayan hizmetler, patlama tamamlandıktan uzun süre sonra soğuk anonim yığın sayfalarını saklayabilir.

Sistem uygulamalarına kalibre edilmiş <memory-budget> beyanları (memory.high esnek sınırlar, genellikle 30 MB ila 190 MB) uygulamanın iki temel avantajı vardır:

  • Proaktif, yerelleştirilmiş sayfa geri alma: Bir sistem işlemi, yapılandırılmış memory.high bütçesini aştığında Linux çekirdeği, sayfa geri alma işlemini özellikle bu cgroup'a yönlendirir. Önce soğuk dosya destekli sayfaları çıkarır ve etkin olmayan anonim sayfaları, global cihaz bellek baskısını beklemeden ZRAM'e sıkıştırır.
  • Ön planda çalışan uygulamalar ve önbelleğe alınmış uygulama havuzu için daha fazla kullanılabilir RAM: Her zaman açık sistem hizmetlerinde soğuk dosya önbelleklerinin sınırlandırılması, cihaz genelinde onlarca ila yüzlerce megabayt fiziksel RAM'i geri kazanır. Bu sayede kullanıcı arayüzü takılmaları azalır, kamera başlatma baskısı düşer ve önbelleğe alınmış durumda daha fazla kullanıcı uygulaması etkin kalır.

Sistem uygulaması bellek bütçelerini yapılandırma

Sistem uygulamaları, genel uygulamalarla aynı <memory-budget> manifest söz dizimini, işlem durumu basamaklamasını, ekran yoğunluğu ölçeklendirmesini ve son eşleşen yan tümce çözümleme kuralını kullanır. Özelliklerin tam listesi için XML özellik referansı'na bakın.

OEM'ler, <memory-budget> öğelerini doğrudan bir sistem uygulamasının AndroidManifest.xml öğesinde tanımlayabilir veya Android.bp içindeki additional_manifests özelliğini kullanarak ayrı bir XML dosyasından birleştirebilir. AOSP, referans sistem uygulaması bütçelerini bağımsız *-budget.xml dosyalarında (temel platform paketleri için frameworks/base/core/memory_budgets/ içinde veya packages/modules/NetworkStack/memory_budgets/, packages/modules/AppSearch/apk/ ve packages/services/Telephony/ gibi bağımsız modüllerle birlikte) depolar ve bunları additional_manifests ile ekler:

android_app {
    name: "TeleService",
    manifest: "AndroidManifest.xml",
    additional_manifests: ["Telephony-budget.xml"],
    // ...
}

Paket düzeyinde (UID) ve işlem düzeyinde (PID) kapsam belirleme

Paket düzeyinde temel bütçe (<application>) veya çoklu işlem bütçesi (<processes><process>) bildirmeniz, çekirdeğin memory.high değerini UID cgroup düzeyinde (/sys/fs/cgroup/uid_<uid>/memory.high) mi yoksa PID başına cgroup düzeyinde (/sys/fs/cgroup/uid_<uid>/pid_<pid>/memory.high) mi uygulayacağını belirler. Bu durum Şekil 4'te gösterilmektedir:

  • Paket düzeyinde (<application>) bütçe: APK, kendi özel UID'si altında tek bir işlem çalıştırdığında (ör. Bluetooth, Nfc, NetworkStack, CalendarProvider, Traceur veya AppSearch) kullanın.
  • İşlem düzeyinde (<processes><process>) bütçe: APK, diğer sistem paketleriyle android:sharedUserId (ör. UID 1001 ile android.uid.phone veya UID 1000 ile android.uid.system) paylaştığında bu bütçeyi kullanın. Böylece, bu UID'yi paylaşan diğer işlemler birlikte kısıtlanmaz. Tek bir APK, farklı bellek rollerine sahip birden fazla işlem (ör. arka plan MediaProvider daemon'u ve :PhotoPicker kullanıcı arayüzü alt işlemi) çalıştırdığında da bu bütçeyi kullanabilirsiniz.

Özel UID'ler için UID düzeyinde memory.high yaptırımını, paylaşılan sistem UID'leri ve çok işlemli APK'lar için PID başına memory.high yaptırımıyla karşılaştıran Cgroup v2 hiyerarşisi

Şekil 4. UID düzeyinde ve PID düzeyinde bellek tavanları.

Aşağıdaki örnekte, RAM katmanlı bütçeleri varsayılan MediaProvider işlemine (<process>) ve ekran ölçekli bütçeyi :PhotoPicker kullanıcı arayüzü işlemine göre kapsayan MediaProvider-budget.xml gösterilmektedir. Her android:maxDeviceRamMb özelliği, toplam fiziksel RAM'i (MemTotal) belirtilen MB eşiğinde veya altında olan cihazlarla eşleşir (veya atlandığında herhangi bir RAM kapasitesi için geçerli olur). Yan tümceler, kısıtlanmamış varsayılandan en küçük maxDeviceRamMb eşiğine doğru sıralanır. Böylece son eşleşen yan tümce çözümleme kuralı, geçerli en dar katmanı seçer:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.providers.media.module">
    <uses-sdk android:targetSdkVersion="10000" />
    <application>
        <processes>
            <process>
                <memory-budget
                    android:maxMb="85" />
                <memory-budget
                    android:maxMb="75"
                    android:maxDeviceRamMb="12288" />
                <memory-budget
                    android:maxMb="60"
                    android:maxDeviceRamMb="8192" />
            </process>
            <process android:process=":PhotoPicker">
                <memory-budget
                    android:maxMb="85"
                    android:additionalBytesPerDisplayPixel="25" />
            </process>
        </processes>
    </application>
</manifest>

AOSP referans bütçeleri Google Pixel cihazlarda nasıl kalibre edildi?

AOSP'deki referans sistem uygulaması bellek bütçeleri, 6 GB ila 16 GB fiziksel RAM (6 GB, 8 GB, 12 GB ve 16 GB telefonlar, katlanabilir cihazlar ve tabletler dahil) ve yaklaşık 1,2 MP (720×1600) ila yaklaşık 4,5 MP (2076×2152) ekran çözünürlükleri sunan Google Pixel cihazlarda kalibre edilmiştir.

Kalibrasyon, iki tamamlayıcı veri kaynağını birleştirdi: filo genelinde cgroup v2 alan telemetrisi ve kritik kullanıcı yolculukları (CUJ'ler) genelinde kontrollü fiziksel cihaz memory.high taramaları.

Filo genelinde cgroup v2 telemetri analizi

Cihaz filosundan periyodik cgroup v2 anlık görüntüleri toplandı ve fiziksel RAM katmanına (≤8 GB, 12 GB ve ≥16 GB) ve işlem durumu grubuna (foreground, perceptible, background ve cached) göre dilimlendi. İstatistiksel analizde altı ilke temel alındı:

  • memory.current değerini çalışma kümesi ve geri kazanılabilir dosya önbelleği olarak ayırma: memory.high, yerleşik cgroup ücretini (memory.current) yönettiği için her anlık görüntü, memory.stat kullanılarak anonim yığın (anon), değiştirilen anonim sayfalar (swap) ve dosya destekli sayfa önbelleği (file) olarak ayrıldı (Şekil 5'te gösterildiği gibi). Sıkıştırılamayan toplam anonim talep (P99'da anon + swap), bütçe için minimum çalışma kümesi tabanını belirler. Böylece işlem, ZRAM tükenme riskiyle karşılaşmaz. memory.current P99 ile anon + swap P99 arasındaki büyük fark ise önbelleğin eşlenmemiş ve soğuk olması koşuluyla memory.high tarafından geri alınabilecek dosya sayfası önbelleğini gösterir.
  • memory.high tarafından geri alınamayan belleği hesaba katın: Tüm dosya ve paylaşılan bellekler soğuk önbellek değildir. Kilitli sayfalar (memory.stat içinde unevictable, örneğin mlock ile kilitli paylaşılan bellek veya ana makine işlemleri uygulamanın cgroup'una ücretlendirilen bir sanal makinenin kilitli misafir RAM'i) bütçenin altında kesin bir alt sınır belirler ve eşlenen sayfalar (file_mapped) genellikle etkin çalışma grubunun bir parçasıdır. Dosya belleğini geri alınabilir olarak değerlendirmeden önce unevictable, shmem ve file_mapped değerlerini kontrol edin. Örneğin, AppSearch belleğin yaklaşık 100 MB'ı kilitli ve çıkarılamaz. Bu nedenle, bütçesi bu alt sınırı ve etkin ana makine çalışma grubunu kapsar. Ayrıca kilitli bölgenin büyümesi için de yer vardır.
  • Boşta kalma durumundaki seyreltmeyi filtreleme: İçerik sağlayıcılar (CalendarProvider) ve isteğe bağlı geliştirici araçları (Traceur), alan anlık görüntülerinin% 70 ila% 99,9'unu yaklaşık 1 MB ila 3 MB arasında boşta geçirir. Tüm anlık görüntülerde ham yüzdelik dilimlerin hesaplanması, P95 ve P99 tahminlerini ciddi şekilde azaltır. Bunun yerine, yüzdelik dilimler ve güven aralıkları, seyreltilmemiş etkin anlık görüntüler (CACHED anlık görüntüleri ve boşta olan referans anlık görüntüleri filtrelenerek) üzerinden hesaplandı.
  • Cihaz kümesine göre gruplandırılmış güven aralıkları kullanın: Tek bir cihaz zaman içinde birçok periyodik anlık görüntüye katkıda bulunduğundan, anlık görüntüleri bağımsız örnekler olarak ele almak kuyruk belirsizliğini olduğundan az gösterir. Tüm P95 ve P99 çalışma kümesi tahminleri, cihaz kümesine göre %95 güven aralıkları (etkin örneklem boyutu olarak farklı cihaz sayısı N_dev kullanılarak) kullanılarak değerlendirildi.
  • memory.peak ile geçici artışları hesaba katın: Periyodik örnekleme, kısa süreli ve yüksek tahsisatlı artışları (ör. NetworkStack giriş portalı TLS doğrulaması ve eşzamanlı DNS probları veya Bluetooth A2DP ve BLE başlatma) kaçırabilir. Anlık yoğunluk gösteren hizmetlerde bütçeler, RAM katmanları genelinde çekirdek memory.peak kullanımının en yüksek olduğu noktaların %90 ila %95'ini kapsayacak şekilde boyutlandırıldı.
  • RAM katmanının cihaz neslini değil, RAM'i yansıttığını doğrulayın: Daha yeni cihazlar hem daha fazla RAM'e hem de daha fazla özelliğe sahip olma eğilimindedir. Bu nedenle, RAM katmanıyla birlikte büyüyen bir çalışma grubu aslında özelliklerle birlikte büyüyor olabilir. maxDeviceRamMb katmanı eklemeden önce verileri cihaz modeline göre dilimleyin. Örneğin, com.android.phone aynı neslin 12 GB ve 16 GB telefonlarında aynı P99 anon + swap'a (~85-90 MB) ulaşırken daha eski bir 12 GB katlanabilir telefon 40 MB kullanır. Bu nedenle, bütçesi RAM katmanı olmayan tek bir değer kullanır. Böylece, daha yeni telefon özelliklerini sunan daha düşük RAM'li bir cihazın bütçesi yetersiz kalmaz.

Cgroup belleğinin zaman içinde sıkıştırılamayan anonim çalışma kümesine, etkin dosya önbelleği penceresine ve memory.high'ın ötesinde geri kazanılan soğuk tek seferlik dosya önbelleğine ayrıştırılması

Şekil 5. Çalışma kümesi ve geri kazanılabilir dosya önbelleği.

Fiziksel cihaz CUJ ve ekran ölçeklendirme taramaları

Telemetriden türetilen bütçeleri doğrulamak ve ekrana orantılı bütçeleri (ör. :PhotoPicker) ve duruma özgü arka plan bütçelerini (ör. Traceur) kalibre etmek için 6 GB ila 16 GB RAM'e sahip fiziksel cihazlarda canlı memory.high taramaları yapıldı:

  • Sıfır yeniden hata dizini bulma: Uçtan uca CUJ'leri (ör. hızlı fotoğraf ızgarası kaydırma, albüme göz atma, tam ekran yüksek çözünürlüklü fotoğraf ve video önizleme kaydırma, iz kaydetme ve kaydetme) çalıştırırken cgroup memory.stat sayaçları (workingset_refault_anon, workingset_refault_file, pgscan ve pgsteal) ile memory.events (high) ölçülürken memory.high azaltıldı. Şekil 6'da gösterildiği gibi, optimum bütçe sıfır yeniden hata dizininin hemen üzerinde yer alır. Sıfır yeniden hata diz, çekirdeğin etkin çalışma kümesi thrashing'ini (workingset_refault == 0) tetiklemeden soğuk tek seferlik dosya önbelleğini (pgsteal > 0) geri aldığı eşiktir.
  • Ekran pikseli ölçeklendirmesini farklı çözünürlüklerde doğrulama: Yaklaşık 1,2 MP (720×1600) ile yaklaşık 4,5 MP (2076×2152 katlanmamış iç ekran) arasında değişen dört fiziksel ve emüle edilmiş ekran çözünürlüğünde yapılan:PhotoPicker testler, etkin Glide ve ViewPager2 bitmap çalışma setinin ekran piksel sayısıyla doğrusal olarak ölçeklendiğini doğruladı. Ekran dışı referans değeri de cihaza göre değişir: Neredeyse aynı piksel sayısında, sıfır yeniden hata diz noktası, 16 GB katlanabilir cihazın dış ekranında yaklaşık 140 MB, 6 GB telefonda ise 110 ila 125 MB arasındaydı. 85 MB'lık bir taban değer ve ekran pikseli başına 25 bayt (android:maxMb="85" ve android:additionalBytesPerDisplayPixel="25"), test edilen her ekranda ölçülen büküm noktasının üzerinde kalır (HD+'ta yaklaşık 110 MB, FHD+'ta yaklaşık 145 MB ve katlanmamış ekranlarda yaklaşık 190 MB).
  • Arka plan durumlarında ART çöp toplama işlemini doğrulama: cgroup v2'de, Zygote tarafından paylaşılan boot.art ve çerçeve görüntü sayfaları, Zygote'un cgroup'una bağlı kalır ve ART eşzamanlı işaretleme-sıkıştırma (CMC) çöp toplama işlemi sırasında bağışık alan olarak değerlendirilir. Stres testi, bir sistem kullanıcı arayüzü uygulaması background durumuna geçtiğinde memory.high sınırını sıkılaştırmanın (ör. Traceur cihazda 30 MB'a) GC çöp toplama veya takas etkinliğine neden olmadan özel yığın ve sayfa önbelleğini temiz bir şekilde sınırladığını doğruladı.

CUJ sırasında memory.high değeri düşürüldüğünde soğuk önbellek geri kazanımı (pgsteal) ve çalışma kümesi thrashing'i (workingset_refault) grafiği, sıfır refault dizini ve hedef bütçeyi vurgular.

Şekil 6. CUJ sırasında sıfır yeniden hata dizini bulma.

AOSP referans sistem uygulaması bütçelerinin özeti

Aşağıdaki tabloda, AOSP'deki kalibre edilmiş referans bütçeler RAM katmanlarına ve işlem durumlarına göre özetlenmiştir:

Sistem paketi veya işlemi Kapsam ≤8 GB RAM 12 GB RAM ≥16 GB RAM Birincil kalibrasyon sürücüsü
com.android.bluetooth UID (<application>) 80 MB 95 MB 110 MB P90 kullanım ömrü memory.peak patlamalarını (~75 ila 110 MB) ve >2 kat P99 etkin memory.current değerini kapsar.
com.android.nfc UID (<application>) 50 MB 60 MB 60 MB Etkin ana kart emülasyonu P99 (yaklaşık 50 MB'a kadar) ve P90 ila P95 memory.peak değerlerini kapsar ve soğuk dosya önbelleğini kırpar.
com.android.providers.calendar UID (<application>) 70 MB varsayılan (ön plan)
50 MB perceptible ve background
Etkin çalışma kümesi, RAM katmanları arasında değişmez. Arka plan bütçesi, senkronizasyonlar sırasında SQLite sayfa önbelleğini kırparak hatırlatıcı alarmlar için anonim boşluk bırakır.
com.android.traceur UID (<application>) 85 MB varsayılan (ön plan ve algılanabilir)
30 MB background
Etkin izleme kaydı ve dışa aktarma sırasında 85 MB'lık tam boşluk payını korur (TraceService). Boşta ve yayın durumunu ise 30 MB ile sınırlar.
com.android.providers.media.module (ana) PID (<process>) 60 MB 75 MB 85 MB Soğuk SQLite ve küçük resim dosyası önbelleğini geri alırken P99 anon + swap üzerinde yaklaşık 10 ila 30 MB boş alan sağlar.
com.android.providers.media.module:PhotoPicker PID (<process>) 85 MB + piksel başına 25 bayt
(HD+'ta yaklaşık 110 MB, FHD+'ta yaklaşık 145 MB, yaklaşık 4,5 MP katlanabilir cihazda yaklaşık 190 MB)
Glide bitmap çalışma kümesi dizine uyacak şekilde ekran piksel sayısıyla (additionalBytesPerDisplayPixel="25") orantılı olarak ölçeklenir.
com.android.networkstack UID (<application>) 65 MB 70 MB 85 MB Çoğunlukla anonim bellek, giriş portalı TLS, DNS ve DHCP artışlarını kapsayacak şekilde P95 kullanım ömrü memory.peak olarak boyutlandırılmıştır.
com.android.appsearch.apk UID (<application>) 130 MB Kilitli bölgenin büyümesi için yer bırakarak yaklaşık 100 MB kilitli, çıkarılamayan bellek ve yaklaşık 5 MB etkin ana makine çalışma kümesini kapsar. Soğuk sayfa önbelleği (P99'da yaklaşık 330 MB'a kadar) geri alınırken ≥125 MB'ta sıfır yeniden hata ölçüldü.
com.android.phone (TeleService) PID (<process>) 120 MB Paylaşılan UID 1001'de PID başına kapsamlı. Çalışma kümesi, RAM yerine cihaz neslini izler. Bu nedenle, tek bir bütçe, model başına en yüksek P99'un yaklaşık 30 MB üzerindedir anon + swap.

OEM'ler kendi cihazları için sistem uygulaması bütçelerini nasıl yeniden kalibre edebilir?

Sistem uygulamalarını özelleştiren (ör. tedarikçi firma Bluetooth profilleri, özel telefon uzantıları veya OEM medya dizinleyicileri ekleme) ya da ek önceden yüklenmiş sistem hizmetleri sunan OEM'ler, mevcut bütçeleri yeniden kalibre edebilir veya donanım portföyleri için yeni *-budget.xml dosyaları oluşturabilir.

Etkin cgroup v2 bellek profillerini toplama

Her hedef sistem işlemi için, temsili iş yükleri ve RAM katmanları genelinde cgroup v2 bellek düğümlerini /sys/fs/cgroup/uid_<uid>/pid_<pid>/ altında okuyun:

  • memory.current: cgroup'a yüklenen mevcut yerleşik bellek (Zygote tarafından paylaşılan sayfalar hariç)
  • memory.peak: İşlem başlangıcından bu yana ulaşılan en yüksek memory.current değeri
  • memory.swap.current: ZRAM'de mevcut sıkıştırılmış takas kullanımı
  • memory.stat: anon, file, pgscan, pgsteal, workingset_refault_anon ve workingset_refault_file dökümü
  • memory.events: high ihlalin kümülatif sayısı (memory.high kısıtlama ve geri alma etkinlikleri)

Dogfood veya saha cihazlarından telemetri verilerini toplarken etkin işlem durumlarını (TOP, FOREGROUND_SERVICE, etkin bağlamalar ve etkin senkronizasyonlar) boşta CACHED veya boşta PERSISTENT durumlarından ayırın. Böylece boşta anlık görüntüler, P95 ve P99 çalışma kümesi hesaplamalarınızı aşağı doğru saptırmaz.

Sıkıştırılamayan yığınları geri kazanılabilir dosya önbelleğinden ayırma

anon + swap için 99. yüzdelik dilimi, memory.current için 99. yüzdelik dilimle karşılaştırın:

  • Dosya önbelleğinin baskın olduğu hizmetler (veritabanı sağlayıcılar, arama dizine ekleyiciler ve günlük daemon'ları gibi file &gg; anon): android:maxMb değerini, P99 anon + swap üzerinde rahat bir boşluk (genellikle 1, 5 ila 4 kat) ve etkin dosya sayfaları için bir çalışma penceresi sağlayacak şekilde ayarlayın. Bu yapılandırma, çekirdeğin anonim yığına dokunmadan soğuk eşlenmemiş dosya sayfalarını sürekli olarak çıkarmasına olanak tanır. unevictable veya file_mapped büyükse (kilitli bellek veya bellekle eşlenen veritabanlarında olduğu gibi) bu ayak izini de çalışma kümesi olarak sayın.
  • Anonim yığın ağırlıklı veya ani artış gösteren hizmetler (anon, memory.current uygulamasının çoğunu oluşturur, örneğin ağ veya bağlantı yığınları): memory.peak uygulamasının P90 ila P95'ini kapsayacak şekilde android:maxMb boyutunu ayarlayın. Böylece geçici ani artışlar, gecikmeye duyarlı iş parçacıklarında eşzamanlı ZRAM takasını tetiklemez.
  • Ekran yoğun kullanıcı arayüzü işlemleri (seçiciler, galeriler veya sistem kullanıcı arayüzü yardımcıları gibi): En düşük ve en yüksek çözünürlüklü ekranlarınızda kullanıcı arayüzü olmayan temel ayak izini ve megapiksel başına artımlı bitmap ayak izini ölçün ve bütçeyi android:maxMb artı android:additionalBytesPerDisplayPixel kullanarak ifade edin.

Fiziksel cihazlarda memory.high değerini temizleme

Derlemeye yeni bir bütçe ayırmadan önce otomatik CUJ testlerinizi çalıştırırken aday sınırları test etmek için am memory-limiter manual komutunu kullanın (veya doğrudan kullanıcı hata ayıklama derlemesinde işlemin memory.high cgroup düğümüne yazın):

# Override memory.high for a specific PID to 60 MB during a CUJ test
adb shell am memory-limiter manual <PID> 60MB

CUJ'den önce ve sonra memory.stat ve memory.events değerlerini izleyin:

  • Bütçe çok düşük: workingset_refault_anon veya workingset_refault_file, CUJ sırasında keskin bir şekilde artıyor, memory.swap.current, etkin ön plan çalışması sırasında sürekli olarak artıyor veya CUJ karesi ya da Binder gecikmesi geriliyor. Bütçeyi varsayılan bütçe eşiğinin üzerine çıkarın.
  • Bütçe çok yüksek: Yoğun dosya akışı veya dizine ekleme iş yüklerinden sonra bile memory.events:high, 0 olarak kalır ve memory.stat içindeki file, soğuk sayfalarla sınırsız bir şekilde büyür. Bütçeyi etkin çalışma kümesine göre daraltın.
  • Bütçe iyi kalibre edilmiş: Kararlı durum memory.current, normal çalışma sırasında memory.high değerinin altında kalır. Yoğun dosya veya önbellek patlamaları sırasında pgsteal, soğuk dosya sayfalarını geri alırken workingset_refault_anon sıfıra yakın kalır ve CUJ gecikmesi değişmez.