Anggaran memori sistem

Di Android 17 dan yang lebih tinggi, platform mengatur memori proses sistem menggunakan dua mekanisme cgroup v2 Linux pelengkap yang berfungsi bersama Pembatas Memori aplikasi umum:

  • Batas minimum perlindungan daemon sistem (SystemMemoryBudgetManager dengan memory.min): Pemesanan memory.min cgroup v2 yang dapat menyesuaikan sendiri (ditetapkan ke 90% dari set kerja residen yang diselesaikan setiap daemon dan dibatasi secara global sebesar 10% dari total RAM fisik) melindungi daemon interaktif penting dan proses shell (system_server, surfaceflinger, HAL composer grafis, audioserver, cameraserver, netd, SystemUI, dan peluncur Layar utama) di bawah tekanan memori, menggantikan penyematan file PinnerService mlock statis.
  • Batas memori aplikasi sistem (<memory-budget> dengan memory.high): Batas lunak memory.high cgroup v2 yang dikalibrasi workload (biasanya 30 MB hingga 190 MB) yang dideklarasikan dalam file manifes untuk aplikasi sistem persisten dan latar belakang (Bluetooth, Nfc, CalendarProvider, Traceur, MediaProvider, :PhotoPicker, NetworkStack, AppSearch, dan TeleService) secara proaktif mengklaim kembali cache halaman file dingin dan heap anonim pasca-burst sebelum terjadi tekanan memori global.

Tabel berikut membandingkan kedua mekanisme tersebut:

Dimensi Batas perlindungan daemon sistem Batas memori aplikasi sistem
Layanan platform SystemMemoryBudgetManager MemoryLimiter
Kontrol cgroup v2 memory.min hard protection floor Batas atas klaim kembali fleksibel memory.high
Proses target Daemon interaktif yang sangat sensitif terhadap latensi dan UI shell (system_server, surfaceflinger, HAL composer, audioserver, cameraserver, netd, SystemUI, dan aplikasi Home) Aplikasi sistem persisten dan headless, penyedia konten, serta layanan latar belakang (seperti Bluetooth, Nfc, MediaProvider, NetworkStack, AppSearch, dan TeleService)
Model penentuan ukuran Penyesuaian mandiri saat runtime (90% set kerja yang ditetapkan, dibatasi secara global sebesar 10% dari total RAM) tanpa tabel penyesuaian per perangkat Atribut XML manifes <memory-budget> deklaratif yang dikalibrasi berdasarkan tingkat RAM, status proses, dan jumlah piksel layar
Manfaat utama Mencegah jank UI interaktif dan penghentian aktivasi saat memori penuh, sekaligus mengganti daftar file PinnerService mlock statis Terus menghapus cache file satu kali yang tidak aktif dan heap pasca-burst untuk menyisakan lebih banyak RAM fisik bagi aplikasi latar depan dan aplikasi yang di-cache

Untuk mengetahui informasi selengkapnya tentang sintaksis <memory-budget>, atribut XML, API runtime, dan pencatatan memori OS, lihat Menetapkan anggaran memori aplikasi dan Memahami dan memecahkan masalah memori Android.

Melindungi daemon interaktif penting dengan SystemMemoryBudgetManager

SystemMemoryBudgetManager mempertahankan proses yang berada langsung di jalur interaktif pengguna di RAM fisik selama tekanan memori. Daripada menyematkan daftar statis file APK, ODEX, dan VDEX ke dalam memori dengan mlock (seperti yang dilakukan PinnerService untuk config_defaultPinnerServiceFiles dan config_pinnerHomePinBytes), SystemMemoryBudgetManager menetapkan batas minimum memory.min cgroup v2 dinamis ke proses berikut:

  • Slice sistem inti (/sys/fs/cgroup/system): system_server, surfaceflinger, HAL composer grafis, audioserver, cameraserver, dan netd, serta daemon vendor atau sistem native khusus faktor bentuk yang tercantum dalam config_systemMemoryBudgetAdditionalSystemProcesses (misalnya, android.hardware.perceptionhost dan auracamerahal di perangkat XR).
  • Slice aplikasi interaktif (/sys/fs/cgroup/apps): Proses utama paket SystemUI yang dikonfigurasi (config_systemUi) dan proses utama pemegang peran Beranda pengguna saat ini.

Melindungi pemegang peran Beranda bersama config_systemUi akan memastikan cakupan di semua faktor bentuk. Pada faktor bentuk tempat config_systemUi adalah paket kompatibilitas ringan (seperti Wear OS, tempat tampilan jam, notifikasi, dan kartu berjalan di dalam aplikasi Home), shell yang ditampilkan kepada pengguna masih menerima perlindungan set kerja penuh. Jika intent Home di-resolve ke paket config_systemUi, proses akan dilindungi sekali. Hanya proses utama setiap paket (processName == packageName) yang menerima batas perlindungan, sehingga subproses tambahan (seperti :screenshot) tidak menggunakan anggaran perlindungan.

Kebijakan penyesuaian mandiri dan delegasi cgroup tiga tingkat

Karena set kerja daemon interaktif sangat bervariasi di berbagai faktor bentuk dan kapasitas RAM (misalnya, SystemUI menggunakan sekitar 45 MB di smartwatch, 60 MB di ponsel 6 GB, dan 180 MB di ponsel 16 GB), tabel pencarian statis per perangkat menjadi rentan. Sebagai gantinya, SystemMemoryBudgetManager memperoleh batas bawah langsung dari jejak residen setiap proses menggunakan tiga konstanta:

Parameter kebijakan Nilai default Perilaku
Harga minimum per proses 90% dari memory.current yang diselesaikan dikurangi cache file yang tidak dipetakan Melindungi heap anonim, slab, dan kode yang dipetakan panas sambil membiarkan 10% ekor terdingin dapat diklaim kembali sehingga halaman yang benar-benar dingin masih dapat dikeluarkan. Cache file yang tidak dipetakan (max(0, file - shmem - file_mapped) dari memory.stat) dikurangi sebelum menerapkan rasio 90% sehingga cache pemindaian paket booting atau pembacaan aset satu kali tidak meningkatkan batas minimum.
Batas RAM global 10% dari total RAM (config_systemMemoryBudgetLowKb) Cocok dengan guardrail PinnerService config_pinnerMaxPinnedMemoryPercentage. Jika jumlah harga minimum 90% melebihi 10% dari MemTotal, setiap harga minimum akan diperkecil skalanya secara proporsional dengan faktor yang sama.
Frekuensi pembaruan 1, 4, 16, dan 64 dtk setelah dimulai, lalu setiap 30 mnt Seri penyelesaian geometris menyatu pada set kerja pasca-startup setiap daemon tanpa melakukan hardcoding penundaan pemanasan per perangkat, dan refresh status stabil selama 30 menit melacak pertumbuhan dan penyusutan set kerja secara bertahap selama masa pakai perangkat.

Di pengontrol memori Linux cgroup v2 (mm/memcontrol.c:effective_protection), perlindungan memory.min efektif cgroup leaf dibatasi oleh memory.min yang dikonfigurasi pada cgroup induk dan ancestor-nya. Menetapkan memory.min hanya pada direktori pid_<pid> leaf sementara uid_<uid>/memory.min adalah 0 akan menghasilkan perlindungan efektif nol. Sebaliknya, menetapkan memory.min tetap hanya di bagian atas /sys/fs/cgroup/system akan mendistribusikan perlindungan yang tidak diklaim di semua UID dan proses turunan secara proporsional (memory_recursiveprot), sehingga memungkinkan proses diagnostik atau sekunder yang berbagi uid_1000 (android.uid.system) untuk menyedot perlindungan dari surfaceflinger dan audioserver.

Untuk memberikan isolasi per daemon yang tepat, SystemMemoryBudgetManager menulis perlindungan di ketiga tingkat hierarki cgroup v2 pada setiap refresh, seperti yang ditunjukkan pada gambar 1:

  1. Node proses leaf (pid_<pid>/memory.min): Ditetapkan ke batas bawah set kerja 90% (diskalakan) proses.
  2. Node UID (uid_<uid>/memory.min): Ditetapkan ke jumlah persis dari batas bawah leaf pid_* yang dikelola, sehingga proses yang tidak dikelola yang berbagi UID tersebut (seperti daemon AID_SYSTEM atau paket sharedUserId="android.uid.system" lainnya) memiliki memory.min = 0 dan tidak dapat mengklaim perlindungan.
  3. Slice tingkat teratas (/sys/fs/cgroup/system/memory.min dan /sys/fs/cgroup/apps/memory.min): Ditetapkan ke jumlah persis dari uid_* turunannya. Setiap nilai memory.low yang tidak berlaku pada node terkelola akan dihapus menjadi 0, dan setiap direktori uid_* yang dikelola pada pemuatan ulang sebelumnya (seperti peluncur Layar utama sebelumnya setelah pengguna beralih peluncur) akan direset ke 0.

Hierarki perlindungan memory.min cgroup v2 tiga tingkat di seluruh /sys/fs/cgroup/system dan /sys/fs/cgroup/apps, yang menunjukkan batas bawah proses leaf yang dijumlahkan ke dalam node UID dan slice, sementara proses seinduk yang tidak dilindungi tetap berada di angka nol

Gambar 1. Delegasi batas perlindungan tiga tingkat di seluruh slice cgroup.

Alasan memory.min digunakan, bukan memory.low pada kernel MGLRU

Di LRU Multi-Generasi (MGLRU, mesin klaim ulang halaman default di kernel Android 6.6 dan yang lebih baru), memory.low dan memory.min berperilaku berbeda di mm/vmscan.c:shrink_one:

  • memory.low (penundaan sekali-proses): Cgroup yang penggunaannya di bawah memory.low diputar ke ujung LRU memcg (MEMCG_LRU_TAIL) dan dilewati untuk satu proses klaim kembali. Pada tahap berikutnya di bawah tekanan memori yang berkelanjutan, kernel akan mengklaim kembali cgroup secara penuh dan mencatat peristiwa MEMCG_LOW ke dalam log. Dalam uji stres perangkat fisik dengan pemboros memori anonim yang meningkat hingga 85% dari RAM fisik, memory.low memungkinkan SystemUI di smartwatch menyusut dari ~45 MB menjadi ~5 hingga 10 MB dan audioserver di perangkat foldable 16 GB turun dari 15 MB menjadi 2 MB dibandingkan dengan batas minimum ~14 MB.
  • memory.min (batas perlindungan ketat): Cgroup yang penggunaannya di bawah memory.min akan dilewati oleh klaim ulang global. Seperti yang ditunjukkan pada gambar 2, di bawah beban kerja tekanan RAM 85% yang sama, memory.min hanya melepaskan 10% tail paling dingin dari setiap daemon dan menahan SystemUI, surfaceflinger, dan audioserver pada batas bawah 90% tanpa refault anonim dan tanpa peningkatan penghentian proses lmkd.

memory.min memberikan pemesanan fisik yang ketat yang cocok dengan perlindungan penyematan PinnerService mlock yang digantikannya, dengan keuntungan bahwa LRU kernel (bukan daftar file statis) memilih kode hot, heap, dan halaman grafis yang tetap berada di memori.

Perbandingan memori tetap daemon saat tekanan memori sistem meningkat dari 40% menjadi 95% RAM fisik, yang menunjukkan memory.min bertahan pada batas bawah 90% sementara memory.low turun setelah satu kali penundaan MGLRU

Gambar 2. Retensi set kerja daemon di bawah tekanan memori yang meningkat.

Booting pra-pemanasan dan reklamasi cache file yang tidak dipetakan setelah booting

Mengganti mlock permanen PinnerService dari config_defaultPinnerServiceFiles memerlukan koordinasi dua perilaku waktu booting:

  • Pra-pemanasan booting latar belakang satu kali (PinnerService): Melewati PinnerService mlock tanpa memanaskan cache halaman akan mengalihkan pembacaan disk SystemUIAPK, ODEX, dan VDEX sebesar ~95 MB ke jalur booting sinkron saat SystemUI dimulai (OnBootPhase_550), sehingga menambahkan 300 hingga 450 md ke penyelesaian booting. Memanggil madvise(MADV_WILLNEED) tidak cukup karena force_page_cache_ra di kernel menjepit satu panggilan MADV_WILLNEED ke satu jendela readahead (biasanya 128 KB hingga 2 MB). Sebagai gantinya, saat SystemMemoryBudgetManager.shouldSkipDefaultSystemPinning aktif, PinnerService memetakan setiap file di config_defaultPinnerServiceFiles pada thread latar belakang selama onStart, mengisi file secara sinkron ke dalam cache halaman dengan Os.mlock, dan segera memanggil Os.munlock, munmap, dan close. Hal ini mempertahankan waktu booting cepat sekaligus tidak meninggalkan byte yang terkunci secara permanen sehingga halaman cold startup dapat dihapus nanti.
  • Mengecualikan dan mengklaim kembali cache pemindaian paket booting system_server: Selama booting, PackageManagerService memindai APK yang diinstal, sehingga menyisakan 1,5 hingga 2,5 GB cache halaman file dingin yang tidak dipetakan yang dibebankan ke cgroup system_server. Jika disertakan dalam penghitungan memory.min dari system_server, cache cold boot tersebut akan memenuhi batas RAM global 10% dan secara proporsional memperkecil skala batas perlindungan surfaceflinger, SystemUI, dan audioserver. Untuk mencegah kekurangan batas, SystemMemoryBudgetManager membaca memory.stat untuk system_server, menghitung cache file yang tidak dipetakan sebagai max(0, file - shmem - file_mapped), dan mengurangi cache yang tidak dipetakan tersebut dari memory.current sebelum menghitung batas bawah 90%, seperti yang ditunjukkan pada gambar 3. Selain itu, 10 detik setelah PHASE_BOOT_COMPLETED, pengelola melakukan penulisan satu kali <unmapped_file> swappiness=0 ke node memory.reclaim dari system_server di Linux 6.2 dan kernel yang lebih baru untuk secara proaktif mengeluarkan cache pemindaian paket dingin tanpa menukar heap anonim atau mengeluarkan DEX dan halaman kode yang dipetakan. Pada kernel lama (seperti android14-6.1) yang menolak swappiness=0 dengan EINVAL, pengelola akan melewati penulisan memory.reclaim, bukan kembali ke penulisan reklamasi yang tidak memenuhi syarat yang akan menukar heap anonim selama booting.

Linimasa memori system_server setelah booting yang menampilkan refresh penyelesaian geometris pada 1, 4, 16, dan 64 detik, pengecualian cache pemindaian paket booting yang tidak dipetakan dari batas bawah memory.min 90%, dan memory.reclaim satu kali dengan swappiness=0

Gambar 3. Konvergensi batas perlindungan dan klaim ulang cache setelah booting.

Persyaratan kernel dan overlay konfigurasi perangkat

SystemMemoryBudgetManager mengandalkan mem_cgroup_calculate_protection di kernel Linux untuk menyebarkan memory.min di seluruh cgroup bertingkat. Kernel umum Android android15-6.6 dan android16-6.12 menyertakan dukungan perlindungan bertingkat MGLRU lengkap secara langsung. Perangkat yang menjalankan android14-6.1 dengan MGLRU yang diaktifkan memerlukan tiga backport upstream di mm/vmscan.c dan mm/memcontrol.c sehingga slice perantara kosong dan cgroup UID menyebarkan perlindungan ke cgroup proses leaf:

  • 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 dapat menyesuaikan atau menonaktifkan SystemMemoryBudgetManager menggunakan overlay resource framework berikut:

  • config_systemMemoryBudgetLowKb (integer, KB): 0 (default) membatasi jumlah semua batas minimum memory.min sebesar 10% dari total RAM fisik. Nilai positif menetapkan batas eksplisit dalam KB, dan nilai negatif menonaktifkan SystemMemoryBudgetManager di perangkat (mempertahankan penyematan mlock statis PinnerService lama).
  • config_systemMemoryBudgetHighKb (bilangan bulat, KB): 0 (default) membiarkan /sys/fs/cgroup/system/memory.high pada max. Nilai positif menetapkan batas atas slice memory.high (harus lebih besar dari atau sama dengan batas bawah).
  • config_systemMemoryBudgetAdditionalSystemProcesses (string-array): Mencantumkan nama proses daemon vendor atau sistem native tambahan yang sangat penting untuk latensi di /sys/fs/cgroup/system (dicocokkan dengan /proc/<pid>/comm atau nama dasar argv[0] di /proc/<pid>/cmdline untuk UID sistem dan vendor di bagian 10000) untuk dilindungi dengan batas minimum memory.min 90% bersama enam daemon sistem default. Gunakan overlay ini daripada menetapkan memory.min di init.rc karena SystemMemoryBudgetManager menghitung ulang uid_<uid>/memory.min sebagai jumlah proses leaf terkelola dan menghapus node uid_* yang tidak dikelola pada setiap refresh. Misalnya, perangkat XR dapat melindungi daemon HAL kamera dan pelacakan spasialnya dengan overlay berikut:

    <string-array translatable="false" name="config_systemMemoryBudgetAdditionalSystemProcesses">
        <item>android.hardware.perceptionhost</item>
        <item>auracamerahal</item>
    </string-array>
    
  • config_systemUi (string): Nama paket aplikasi SystemUI platform, diselesaikan dengan MATCH_SYSTEM_ONLY.

Untuk memeriksa lantai SystemMemoryBudgetManager dan node cgroup yang aktif di perangkat, jalankan:

# 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

Mengikat aplikasi sistem persisten dan latar belakang dengan anggaran memori

Meskipun SystemMemoryBudgetManager melindungi daemon interaktif dari klaim ulang menggunakan batas minimum memory.min, banyak aplikasi sistem dan layanan platform dengan hak istimewa lainnya berjalan di latar belakang dalam waktu lama sebagai proses PERSISTENT, layanan latar depan terikat, atau penyedia konten yang sering dikueri. Tanpa batas memori eksplisit, proses ini tidak dibatasi hingga mencapai batas Pembatas Memori multi-gigabyte (seperti 4 GB hingga 10 GB untuk aplikasi yang terlihat dan 2 GB hingga 5 GB untuk aplikasi latar belakang) atau tekanan memori global memicu aktivitas kswapd dan low-memory killer (lmkd) di seluruh sistem.

Jika tidak dibatasi, proses sistem latar belakang sering kali mengumpulkan sejumlah besar memori dingin yang bukan bagian dari set kerja aktifnya:

  • Cache halaman file tak terbatas: Layanan yang mengindeks media, menelusuri database, atau menyinkronkan tabel kalender dan penyedia (seperti AppSearch, MediaProvider, dan CalendarProvider) memetakan atau melakukan streaming melalui file besar di disk. Tanpa batas memory.high cgroup, halaman bersih yang didukung file dari pembacaan satu kali akan tetap dibebankan ke cgroup proses tanpa batas waktu, sehingga menggunakan ratusan megabyte RAM fisik.
  • Retensi heap anonim pasca-burst: Layanan yang mengalami lonjakan aktivitas sementara, seperti burst penemuan BLE dan audio Bluetooth, validasi TLS captive-portal NetworkStack, atau helper UI yang bertransisi ke latar belakang, dapat mempertahankan halaman heap anonim dingin lama setelah burst selesai.

Menerapkan deklarasi <memory-budget> yang dikalibrasi (batas ringan memory.high, biasanya 30 MB hingga 190 MB) ke aplikasi sistem memberikan dua manfaat utama:

  • Klaim ulang halaman yang proaktif dan dilokalkan: Saat proses sistem melampaui anggaran memory.high yang dikonfigurasi, kernel Linux mengarahkan klaim ulang halaman khusus ke cgroup tersebut, mengeluarkan halaman yang didukung file dingin terlebih dahulu dan mengompresi halaman anonim yang tidak aktif ke ZRAM tanpa menunggu tekanan memori perangkat global.
  • RAM yang lebih banyak tersedia untuk aplikasi latar depan dan kumpulan aplikasi yang di-cache: Membatasi cache file cold di seluruh layanan sistem yang selalu aktif akan mengklaim kembali puluhan hingga ratusan megabyte RAM fisik di seluruh perangkat, sehingga mengurangi jank UI, menurunkan tekanan peluncuran kamera, dan menjaga lebih banyak aplikasi pengguna tetap aktif dalam status di-cache.

Mengonfigurasi anggaran memori aplikasi sistem

Aplikasi sistem menggunakan sintaksis manifes <memory-budget>, cascading status proses, penskalaan kepadatan tampilan, dan aturan resolusi klausa pencocokan terakhir yang sama dengan aplikasi umum. Untuk mengetahui daftar lengkap atribut, lihat referensi atribut XML.

OEM dapat mendeklarasikan elemen <memory-budget> langsung di dalam AndroidManifest.xml aplikasi sistem atau menggabungkannya dari file XML terpisah menggunakan properti additional_manifests di Android.bp. Berdasarkan konvensi, AOSP menyimpan anggaran aplikasi sistem referensi dalam file *-budget.xml mandiri (baik di frameworks/base/core/memory_budgets/ untuk paket platform inti atau bersama modul individual seperti packages/modules/NetworkStack/memory_budgets/, packages/modules/AppSearch/apk/, dan packages/services/Telephony/) dan melampirkannya dengan additional_manifests:

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

Cakupan tingkat paket (UID) versus tingkat proses (PID)

Apakah Anda mendeklarasikan anggaran dasar pengukuran tingkat paket (<application>) atau anggaran multiproses (<processes><process>) menentukan apakah kernel menerapkan memory.high di tingkat cgroup UID (/sys/fs/cgroup/uid_<uid>/memory.high) atau di tingkat cgroup per PID (/sys/fs/cgroup/uid_<uid>/pid_<pid>/memory.high), seperti yang ditunjukkan pada gambar 4:

  • Anggaran tingkat paket (<application>): Gunakan saat APK menjalankan satu proses di bawah UID khususnya sendiri (misalnya, Bluetooth, Nfc, NetworkStack, CalendarProvider, Traceur, atau AppSearch).
  • Anggaran tingkat proses (<processes><process>): Gunakan saat APK berbagi android:sharedUserId (seperti android.uid.phone dengan UID 1001 atau android.uid.system dengan UID 1000) dengan paket sistem lain sehingga proses lain yang berbagi UID tersebut tidak dibatasi bersama, atau saat satu APK menjalankan beberapa proses dengan peran memori yang berbeda (misalnya, daemon MediaProvider latar belakang dan subproses UI :PhotoPicker).

Hierarki cgroup v2 yang membandingkan penerapan memory.high tingkat UID untuk UID khusus dengan penerapan memory.high per PID untuk UID sistem bersama dan APK multiproses

Gambar 4. Batas memori tingkat UID versus tingkat PID.

Contoh berikut menunjukkan MediaProvider-budget.xml, yang mencakup anggaran berjenjang RAM ke proses MediaProvider default (<process>) dan anggaran berskala tampilan ke proses UI :PhotoPicker. Setiap atribut android:maxDeviceRamMb cocok dengan perangkat yang total RAM fisiknya (MemTotal) berada pada atau di bawah batas MB yang ditentukan (atau berlaku untuk kapasitas RAM apa pun jika dihilangkan). Klausa diurutkan dari default yang tidak dibatasi hingga nilai minimum maxDeviceRamMb terkecil sehingga aturan resolusi klausa pencocokan terakhir memilih tingkat yang berlaku paling ketat:

<?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>

Cara anggaran referensi AOSP dikalibrasi di perangkat Google Pixel

Anggaran memori aplikasi sistem referensi di AOSP dikalibrasi di seluruh perangkat Google Pixel yang mencakup RAM fisik 6 GB hingga 16 GB (termasuk ponsel, perangkat foldable, dan tablet 6 GB, 8 GB, 12 GB, dan 16 GB) serta resolusi layar mulai dari ~1,2 MP (720×1600) hingga ~4,5 MP (2076×2152).

Kalibrasi menggabungkan dua sumber data yang saling melengkapi: telemetri lapangan cgroup v2 di seluruh perangkat dan pemindaian memory.high perangkat fisik yang terkontrol di seluruh perjalanan penting pengguna (CUJ).

Analisis telemetri cgroup v2 tingkat fleet

Snapshot cgroup v2 berkala dikumpulkan di seluruh rangkaian perangkat dan dibagi berdasarkan tingkat RAM fisik (≤8 GB, 12 GB, dan ≥16 GB) serta bucket status proses (foreground, perceptible, background, dan cached). Enam prinsip memandu analisis statistik:

  • Menguraikan memory.current menjadi set kerja versus cache file yang dapat diklaim kembali: Karena memory.high mengatur biaya cgroup residen (memory.current), setiap snapshot diuraikan menggunakan memory.stat menjadi heap anonim (anon), halaman anonim yang ditukar (swap), dan cache halaman yang didukung file (file), seperti yang ditunjukkan pada gambar 5. Total permintaan anonim yang tidak dapat dikompresi (anon + swap di P99) menetapkan batas minimum set kerja untuk anggaran sehingga proses tidak berisiko kehabisan ZRAM, sementara kesenjangan yang besar antara memory.current P99 dan anon + swap P99 menunjukkan cache halaman file yang dapat diklaim kembali oleh memory.high, asalkan cache tersebut tidak dipetakan dan dingin.
  • Memperhitungkan memori yang tidak dapat diklaim kembali oleh memory.high: Tidak semua file dan memori bersama adalah cold cache. Halaman yang dikunci (unevictable di memory.stat, seperti memori bersama yang dikunci dengan mlock atau RAM tamu yang dikunci dari virtual machine yang proses host-nya ditagih ke cgroup aplikasi) menetapkan batas minimum di bawah anggaran, dan halaman yang dipetakan (file_mapped) sering kali merupakan bagian dari set kerja aktif. Periksa unevictable, shmem, dan file_mapped sebelum memperlakukan memori file sebagai dapat diklaim kembali. Misalnya, sekitar 100 MB memori AppSearch dikunci dan tidak dapat dikeluarkan, sehingga anggarannya mencakup batas minimum tersebut ditambah set kerja host panasnya, dengan ruang untuk pertumbuhan region yang dikunci.
  • Memfilter dilusi status tidak ada aktivitas: Penyedia konten (CalendarProvider) dan alat developer on demand (Traceur) menghabiskan 70% hingga 99,9% snapshot lapangan tidak ada aktivitas pada ~1 MB hingga 3 MB. Menghitung persentil mentah di semua snapshot akan sangat mengurangi estimasi P95 dan P99. Sebagai gantinya, persentil dan interval kepercayaan dihitung berdasarkan snapshot aktif yang tidak diencerkan (memfilter snapshot CACHED dan snapshot dasar pengukuran tidak ada aktivitas).
  • Gunakan interval keyakinan yang dikelompokkan berdasarkan perangkat: Karena satu perangkat memberikan banyak snapshot berkala dari waktu ke waktu, memperlakukan snapshot sebagai sampel independen akan meremehkan ketidakpastian tail. Semua estimasi set kerja P95 dan P99 dievaluasi menggunakan interval keyakinan 95% yang dikelompokkan menurut perangkat secara konservatif (menggunakan jumlah perangkat yang berbeda N_dev sebagai ukuran sampel efektif).
  • Memperhitungkan lonjakan sementara dengan memory.peak: Pengambilan sampel berkala dapat melewatkan lonjakan alokasi tinggi yang berumur pendek (seperti validasi TLS captive-portal NetworkStack dan pemeriksaan DNS serentak, atau inisialisasi A2DP dan BLE Bluetooth). Untuk layanan bursty, anggaran diukur untuk mencakup persentil ke-90 hingga ke-95 dari batas maksimum memory.peak kernel seumur hidup di seluruh tingkat RAM.
  • Pastikan tingkat RAM mencerminkan RAM, bukan generasi perangkat: Perangkat yang lebih baru cenderung memiliki lebih banyak RAM dan lebih banyak fitur, sehingga set kerja yang berkembang seiring tingkat RAM mungkin sebenarnya berkembang seiring fitur. Sebelum menambahkan tingkat maxDeviceRamMb, bagi data berdasarkan model perangkat. Misalnya, com.android.phone mencapai anon + swap P99 yang sama (~85 hingga 90 MB) pada ponsel 12 GB dan 16 GB dari generasi yang sama, sedangkan perangkat foldable 12 GB yang lebih lama menggunakan 40 MB. Oleh karena itu, anggarannya menggunakan satu nilai tanpa tingkat RAM, sehingga perangkat RAM yang lebih rendah yang mengirimkan fitur telepon yang lebih baru tidak kekurangan anggaran.

Dekomposisi memori cgroup dari waktu ke waktu menjadi set kerja anonim yang tidak dapat dikompresi, jendela cache file aktif, dan cache file satu kali dingin yang diklaim kembali di luar memory.high

Gambar 5. Set kerja versus cache file yang dapat diklaim kembali.

CUJ perangkat fisik dan pemindaian penskalaan layar

Untuk memvalidasi anggaran yang diperoleh dari telemetri dan mengkalibrasi anggaran proporsional tampilan (seperti :PhotoPicker) dan anggaran latar belakang khusus status (seperti Traceur), pemindaian memory.high langsung dijalankan di perangkat fisik yang mencakup RAM 6 GB hingga 16 GB:

  • Menemukan titik lutut kesalahan ulang nol: Saat mendorong CUJ menyeluruh (seperti pengguliran cepat petak foto, penjelajahan album, geser pratinjau foto dan video resolusi tinggi layar penuh, serta rekaman pelacakan dan penyimpanan), memory.high diturunkan saat mengukur penghitung memory.stat cgroup (workingset_refault_anon, workingset_refault_file, pgscan, dan pgsteal) dan memory.events (high). Seperti yang diilustrasikan dalam gambar 6, anggaran optimal berada tepat di atas titik lutut kesalahan ulang nol. Zero-refault knee adalah nilai minimum saat kernel mengklaim kembali cache file satu kali yang dingin (pgsteal > 0) tanpa memicu thrashing set kerja aktif (workingset_refault == 0).
  • Memvalidasi penskalaan piksel tampilan di berbagai resolusi: Pengujian :PhotoPicker di empat resolusi tampilan fisik dan emulasi dari ~1,2 MP (720×1600) hingga ~4,5 MP (layar dalam yang dibentangkan 2076×2152) mengonfirmasi bahwa set kerja bitmap Glide dan ViewPager2 yang aktif diskalakan secara linear dengan jumlah piksel tampilan. Baseline non-tampilan juga bervariasi menurut perangkat: pada jumlah piksel yang hampir sama, titik belok tanpa kesalahan adalah sekitar 140 MB pada layar luar perangkat foldable 16 GB versus 110 hingga 125 MB pada ponsel 6 GB. Dasar pengukuran 85 MB ditambah 25 byte per piksel tampilan (android:maxMb="85" dan android:additionalBytesPerDisplayPixel="25") tetap berada di atas batas yang diukur pada setiap layar yang diuji (~110 MB pada HD+, ~145 MB pada FHD+, dan ~190 MB pada layar yang dibentangkan).
  • Memverifikasi pembersihan sampah memori ART dalam status latar belakang: Di cgroup v2, halaman image framework dan boot.art yang dibagikan Zygote tetap dibebankan ke cgroup Zygote dan diperlakukan sebagai ruang kebal selama pembersihan sampah memori mark-compact (CMC) serentak ART. Pengujian stres mengonfirmasi bahwa saat aplikasi UI sistem bertransisi ke background, pengetatan memory.high (misalnya, menjadi 30 MB di Traceur) akan membatasi heap pribadi dan cache halaman dengan rapi tanpa menyebabkan thrashing GC atau aktivitas pertukaran.

Plot reklamasi cold cache (pgsteal) dan thrashing set kerja (workingset_refault) saat memory.high diturunkan selama CUJ, yang menyoroti titik belok zero-refault dan target anggaran

Gambar 6. Menemukan titik belok zero-refault selama CUJ.

Ringkasan anggaran aplikasi sistem referensi AOSP

Tabel berikut merangkum anggaran referensi yang dikalibrasi di AOSP di seluruh tingkat RAM dan status proses:

Paket atau proses sistem Cakupan RAM ≤8 GB RAM 12 GB RAM ≥16 GB Faktor pendorong kalibrasi utama
com.android.bluetooth UID (<application>) 80 MB 95 MB 110 MB Mencakup burst memory.peak masa aktif P90 (~75 hingga 110 MB) dan memory.current aktif >2x P99.
com.android.nfc UID (<application>) 50 MB 60 MB 60 MB Mencakup Host Card Emulation P99 aktif (hingga ~50 MB) dan P90 hingga P95 memory.peak sambil memangkas cache file dingin.
com.android.providers.calendar UID (<application>) 70 MB default (latar depan)
50 MB perceptible & background
Set kerja aktif tidak bervariasi di seluruh tingkat RAM. Anggaran latar belakang mempertahankan headroom anonim untuk alarm pengingat sekaligus memangkas cache halaman SQLite selama sinkronisasi.
com.android.traceur UID (<application>) 85 MB default (latar depan & terlihat)
30 MB background
Mempertahankan headroom penuh sebesar 85 MB selama perekaman dan ekspor rekaman aktivitas aktif (TraceService), sekaligus membatasi status tidak ada aktivitas dan siaran pada 30 MB.
com.android.providers.media.module (utama) PID (<process>) 60 MB 75 MB 85 MB Menyediakan ruang tambahan sekitar 10 hingga 30 MB di atas P99 anon + swap sekaligus mengklaim kembali cache file thumbnail dan SQLite yang tidak aktif.
com.android.providers.media.module:PhotoPicker PID (<process>) 85 MB + 25 byte per piksel
(~110 MB di HD+, ~145 MB di FHD+, ~190 MB di layar lipat ~4,5 MP)
Menskalakan secara proporsional dengan jumlah piksel tampilan (additionalBytesPerDisplayPixel="25") agar sesuai dengan knee set kerja bitmap Glide.
com.android.networkstack UID (<application>) 65 MB 70 MB 85 MB Sebagian besar memori anonim, berukuran masa aktif P95 memory.peak untuk mencakup burst DHCP, DNS, dan TLS captive portal.
com.android.appsearch.apk UID (<application>) 130 MB Mencakup ~100 MB memori terkunci yang tidak dapat dikeluarkan ditambah set kerja host panas ~5 MB, dengan ruang untuk region terkunci untuk berkembang. Nol kesalahan referensi yang diukur pada ≥125 MB saat cold page cache (hingga ~330 MB di P99) diklaim kembali.
com.android.phone (TeleService) PID (<process>) 120 MB Dicakup per PID pada UID bersama 1001. Set kerja melacak generasi perangkat, bukan RAM, sehingga satu anggaran berada ~30 MB di atas anon + swap P99 tertinggi per model.

Cara OEM dapat mengkalibrasi ulang anggaran aplikasi sistem untuk perangkat mereka sendiri

OEM yang menyesuaikan aplikasi sistem (misalnya, menambahkan profil Bluetooth vendor, ekstensi telepon kustom, atau pengindeks media OEM) atau mengirimkan layanan sistem tambahan yang telah diinstal sebelumnya dapat mengalokasikan ulang anggaran yang ada atau membuat file *-budget.xml baru untuk portofolio hardware mereka.

Mengumpulkan profil memori cgroup v2 aktif

Untuk setiap proses sistem target, baca node memori cgroup v2-nya di bagian /sys/fs/cgroup/uid_<uid>/pid_<pid>/ di seluruh workload dan tingkat RAM yang representatif:

  • memory.current: Memori residen saat ini yang dibebankan ke cgroup (tidak termasuk halaman yang dibagikan Zygote)
  • memory.peak: Batas maksimum puncak memory.current sepanjang waktu sejak proses dimulai
  • memory.swap.current: Penggunaan swap terkompresi saat ini di ZRAM
  • memory.stat: Pengelompokan anon, file, pgscan, pgsteal, workingset_refault_anon, dan workingset_refault_file
  • memory.events: Jumlah kumulatif pelanggaran high (peristiwa throttling dan klaim kembali memory.high)

Saat menggabungkan telemetri dari perangkat dogfood atau lapangan, pisahkan status proses aktif (TOP, FOREGROUND_SERVICE, binding aktif, dan sinkronisasi aktif) dari status CACHED nonaktif atau PERSISTENT nonaktif sehingga snapshot nonaktif tidak memiringkan penghitungan set kerja P95 dan P99 Anda ke bawah.

Memisahkan heap yang tidak dapat dikompresi dari cache file yang dapat diklaim kembali

Bandingkan persentil ke-99 dari anon + swap dengan persentil ke-99 dari memory.current:

  • Layanan yang didominasi cache file (file &gg; anon, seperti penyedia database, pengindeks penelusuran, dan daemon log): Tetapkan android:maxMb untuk memberikan ruang yang nyaman (biasanya 1,5x hingga 4x) di atas P99 anon + swap ditambah jendela kerja untuk halaman file panas. Konfigurasi ini memungkinkan kernel terus mengeluarkan halaman file dingin yang tidak dipetakan tanpa menyentuh heap anonim. Jika unevictable atau file_mapped berukuran besar (seperti dengan memori terkunci atau database yang dipetakan memori), hitung jejak tersebut sebagai set kerja juga.
  • Layanan yang didominasi heap anonim atau bursty (anon merupakan sebagian besar memory.current, seperti stack jaringan atau konektivitas): Ukuran android:maxMb untuk mencakup P90 hingga P95 dari memory.peak sehingga burst sementara tidak memicu swap-out ZRAM sinkron pada thread yang sensitif terhadap latensi.
  • Proses UI yang intensif tampilan (seperti pemilih, galeri, atau helper UI sistem): Ukur jejak non-UI dasar pengukuran dan jejak bitmap inkremental per megapiksel di seluruh tampilan resolusi terendah dan tertinggi, dan nyatakan anggaran menggunakan android:maxMb plus android:additionalBytesPerDisplayPixel.

Menyapu memory.high di perangkat fisik

Sebelum mengalokasikan anggaran baru ke build, gunakan am memory-limiter manual (atau tulis langsung ke node cgroup memory.high proses pada build userdebug) untuk menguji batas kandidat saat menjalankan pengujian CUJ otomatis:

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

Pantau memory.stat dan memory.events sebelum dan setelah CUJ:

  • Anggaran terlalu rendah: workingset_refault_anon atau workingset_refault_file melonjak tajam selama CUJ, memory.swap.current terus bertambah selama pekerjaan latar depan aktif, atau frame CUJ atau latensi Binder mengalami regresi. Tingkatkan anggaran melebihi titik belok default.
  • Anggaran terlalu tinggi: memory.events:high tetap 0 bahkan setelah workload streaming file atau pengindeksan yang berat, dan file di memory.stat bertambah tanpa batas dengan halaman cold. Perketat anggaran untuk set kerja yang aktif.
  • Anggaran dikalibrasi dengan baik: memory.current status stabil tetap berada di bawah memory.high selama operasi normal. Selama burst file atau cache yang berat, pgsteal mengklaim kembali halaman file cold, sementara workingset_refault_anon tetap mendekati nol dan latensi CUJ tidak berubah.