Pembatas Memori

Android 17 dan yang lebih tinggi menyertakan Pembatas Memori, layanan sistem yang memantau dan membatasi penggunaan memori proses aplikasi menggunakan cgroup v2 Linux. Pembatas Memori mencegah setiap aplikasi mengonsumsi memori sistem yang tidak proporsional, sehingga mengurangi tekanan memori secara keseluruhan dan mencegah penghentian paksa yang agresif akibat kehabisan memori pada proses latar depan dan proses yang di-cache yang penting.

Mekanisme

Pembatas Memori terintegrasi dengan Activity Manager Service (AMS) untuk melacak peristiwa siklus proses proses dan perubahan status. Pembatas Memori menerapkan batas memori menggunakan hierarki cgroup v2 kernel Linux.

Untuk mendukung Pembatas Memori, kernel perangkat harus mengaktifkan cgroup v2 dan pengontrol memory. Layanan ini secara khusus mengandalkan atribut berikut:

memory.high
Batas yang dapat dilewati. Jika batas ini terlampaui, proses akan dibatasi dan kernel akan mencoba mengklaim kembali halaman secara proaktif dari proses tersebut.
memory.swap.max
Membatasi jumlah maksimum ruang swap (seperti ZRAM) yang dapat digunakan proses.

Dampak pada aplikasi

Aplikasi yang beroperasi dalam batas memorinya tidak akan terpengaruh oleh Pembatas Memori.

Saat aplikasi melampaui batas memory.high, kernel akan mengeluarkan memori yang didukung file bersih aplikasi dan menukar memori anonim yang tidak aktif untuk menjaga aplikasi tetap dalam batas. Sebagai akibat dari aktivitas pengosongan dan pertukaran halaman ini, aplikasi mungkin mengalami throttling eksekusi sementara, tetapi terus berjalan.

Dalam situasi ekstrem—seperti kebocoran memori yang tidak terkontrol saat aplikasi terus mengalokasikan memori anonim setelah ruang swap habis—aplikasi gagal mengalokasikan memori dan dihentikan.

Pemantauan proses

Pembatas Memori memantau proses aplikasi (UID >= 10000) secara default. Proses sistem inti dikecualikan untuk menjaga stabilitas sistem yang penting.

Pembatas Memori menetapkan batas memori berdasarkan status visibilitas proses:

  • Proses yang terlihat: Proses yang menghosting UI yang terlihat oleh pengguna (seperti aktivitas yang saat ini difokuskan atau interaksi aktif). Karena menampilkan UI memerlukan set kerja yang lebih besar untuk pipeline rendering dan grafis, proses yang terlihat menerima batas memori yang lebih besar.

  • Proses tidak terlihat: Proses yang melakukan pekerjaan di latar belakang tanpa menampilkan UI (seperti layanan latar belakang atau penerima siaran). Karena tidak merender komponen UI, widget ini beroperasi di bawah batas yang lebih ketat.

Tabel berikut memetakan status proses tertentu ke klasifikasi batas memori:

Status prosesBatas memori
PERSISTENTTidak dibatasi
PERSISTENT_UITidak dibatasi
TOPTerlihat
BOUND_TOPTerlihat
FOREGROUND_SERVICETidak terlihat
BOUND_FOREGROUND_SERVICETidak terlihat
IMPORTANT_FOREGROUNDTerlihat
IMPORTANT_BACKGROUNDTidak terlihat
TRANSIENT_BACKGROUNDTidak terlihat
BACKUPTidak terlihat
SERVICETidak terlihat
RECEIVERTidak terlihat
TOP_SLEEPINGTerlihat
HEAVY_WEIGHTTidak terlihat
HOMETidak terlihat
LAST_ACTIVITYTidak terlihat
CACHED_ACTIVITYDi-cache
CACHED_ACTIVITY_CLIENTDi-cache
CACHED_RECENTDi-cache
CACHED_EMPTYDi-cache

Dalam status di-cache, proses dibekukan, lalu diklaim kembali secara maksimal.

Jika suatu proses melebihi batas memory.high yang ditetapkan, Pembatas Memori akan mendeteksi peristiwa tersebut dan dapat memicu tindakan diagnostik, seperti mengambil profil memori atau mencatat anomali ke statsd.

Konfigurasi

Di Android 17 dan yang lebih tinggi, Pembatas Memori dikonfigurasi menggunakan file konfigurasi platform standar di partisi sistem di /system/etc/memory-limiter-config.xml.

Format XML

File konfigurasi mengikuti skema yang ditentukan dalam memory-limiter-config.xsd. File ini menentukan beberapa set batas yang diurutkan berdasarkan memori yang tersedia; layanan akan memilih set batas pencocokan tertinggi berdasarkan RAM yang tersedia di perangkat. Semua nilai memori ditentukan dalam mebibyte (MiB).

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <!-- RAM boundaries account for MemTotal excluding carve-outs. -->
    <limitSet>
      <!-- Limits for 16GB RAM device [14336, 18432): 10G/5G/5G/5G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>18432</maximumAllowedMemTotal>
      <memVisible>10240</memVisible>
      <memNotVisible>5120</memNotVisible>
      <swapVisible>5120</swapVisible>
      <swapNotVisible>5120</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 12GB RAM device [9216, 14336): 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>9216</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>14336</maximumAllowedMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 8GB RAM device [6800, 9216): 5G/3G/3G/3G -->
      <minimumRequiredMemTotal>6800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>9216</maximumAllowedMemTotal>
      <memVisible>5120</memVisible>
      <memNotVisible>3072</memNotVisible>
      <swapVisible>3072</swapVisible>
      <swapNotVisible>3072</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 6GB RAM device [4800, 6800): 4G/2G/2G/2G -->
      <minimumRequiredMemTotal>4800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>6800</maximumAllowedMemTotal>
      <memVisible>4096</memVisible>
      <memNotVisible>2048</memNotVisible>
      <swapVisible>2048</swapVisible>
      <swapNotVisible>2048</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 4GB RAM device [3200, 4800): 2G/1G/1G/1G -->
      <minimumRequiredMemTotal>3200</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>4800</maximumAllowedMemTotal>
      <memVisible>2048</memVisible>
      <memNotVisible>1024</memNotVisible>
      <swapVisible>1024</swapVisible>
      <swapNotVisible>1024</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
Bilangan bulat positif yang mengidentifikasi versi konfigurasi. Nilai ini harus berupa 1.
minimumRequiredMemTotal

MemTotal sistem minimum (dalam MiB, batas bawah inklusif) yang diperlukan agar set batas ini berlaku. Layanan ini mengevaluasi hal ini terhadap total memori yang tersedia yang dilaporkan oleh kernel di /proc/meminfo.

Memahami alokasi dan batas memori: Nilai MemTotal kernel mencerminkan DRAM fisik yang dapat diakses oleh sistem operasi setelah alokasi memori hardware dan firmware dikurangi. Carve-out mencadangkan RAM untuk komponen hardware khusus seperti GPU, modem baseband, ISP kamera, lingkungan eksekusi yang aman, dan hypervisor, yang biasanya menggunakan antara 500 MiB dan lebih dari 2 GiB memori fisik.

Karena MemTotal lebih rendah daripada DRAM fisik yang diiklankan perangkat, nilai minimum minimumRequiredMemTotal menyertakan margin untuk carve-out ini. Misalnya, konfigurasi yang menargetkan perangkat 16 GB menentukan batas bawah 14336 (14 GiB), bukan 16384 (16 GiB), dan tingkat untuk perangkat 12 GB menentukan batas bawah 9216 (9 GiB). Hal ini memastikan bahwa setiap perangkat cocok dengan tingkat yang diinginkan, terlepas dari variasi pembagian di tingkat board.

maximumAllowedMemTotal

MemTotal sistem maksimum (dalam MiB, batas atas eksklusif) agar set batas ini berlaku. Jika MemTotal lebih besar dari atau sama dengan batas ini, batas yang ditetapkan tidak berlaku. Untuk perangkat dengan 18.432 MiB atau lebih atau untuk perangkat dengan kurang dari 3.200 MiB, Pembatas Memori tidak menerapkan batasan, sehingga proses tidak dibatasi.

memVisible

Batas memori ringan (memory.high) dalam MiB yang diterapkan ke proses yang terlihat.

memNotVisible

Batas memori sementara (memory.high) dalam MiB yang diterapkan ke proses yang tidak terlihat.

swapVisible

Batas ruang swap (memory.swap.max) dalam MiB yang diterapkan ke proses yang terlihat.

swapNotVisible

Batas ruang swap (memory.swap.max) dalam MiB yang diterapkan ke proses yang tidak terlihat.

Batas platform standar

Di Android 17 dan yang lebih tinggi, platform menentukan batas memori dan swap standar di /system/etc/memory-limiter-config.xml di seluruh tingkat RAM fisik umum menggunakan interval rentang [floor, ceiling):

RAM fisik target Rentang MemTotal [floor, ceiling)
(minimumRequiredMemTotal,
maximumAllowedMemTotal)
Batas memori yang terlihat
(memVisible)
Batas memori tidak terlihat
(memNotVisible)
Batas swap yang terlihat
(swapVisible)
Batas penukaran tidak terlihat
(swapNotVisible)
16 GB [14336, 18432) MiB 10.240 MiB (10 GiB) 5.120 MiB (5 GiB) 5.120 MiB (5 GiB) 5.120 MiB (5 GiB)
12 GB [9216, 14336) MiB 8.192 MiB (8 GiB) 4.096 MiB (4 GiB) 4.096 MiB (4 GiB) 4.096 MiB (4 GiB)
8 GB [6800, 9216) MiB 5.120 MiB (5 GiB) 3.072 MiB (3 GiB) 3.072 MiB (3 GiB) 3.072 MiB (3 GiB)
6 GB [4800, 6800) MiB 4.096 MiB (4 GiB) 2.048 MiB (2 GiB) 2.048 MiB (2 GiB) 2.048 MiB (2 GiB)
4 GB [3200, 4800) MiB 2.048 MiB (2 GiB) 1.024 MiB (1 GiB) 1.024 MiB (1 GiB) 1.024 MiB (1 GiB)

Prinsip batas memori

Konfigurasi Pembatas Memori dirancang berdasarkan prinsip platform berikut:

  • Konsistensi ekosistem dan kompatibilitas aplikasi: Batas memori yang konsisten di seluruh perangkat memastikan performa aplikasi yang dapat diprediksi di seluruh ekosistem Android. Aplikasi dikembangkan dan diuji berdasarkan ekspektasi memori standar; mempertahankan batas platform yang seragam akan menghindari throttling yang tidak terduga atau penghentian dini.

  • Alokasi resource proporsional: Batas platform dikalibrasi sesuai dengan kapasitas RAM fisik:

    • Proses yang terlihat: Mengalokasikan sekitar 1/2 hingga 2/3 dari total RAM fisik untuk mendukung workload UI, komposisi, dan rendering yang aktif.
    • Proses yang tidak terlihat: Mengalokasikan sekitar 1/4 hingga 1/3 dari total RAM fisik untuk tugas latar belakang.
  • Penerapan universal: Batas berlaku secara seragam untuk semua proses aplikasi di perangkat (UID >= 10000), termasuk aplikasi sistem dan OEM bawaan. Pembatas Memori tidak mendukung daftar yang diizinkan untuk mengecualikan aplikasi tertentu, sehingga memastikan tata kelola memori yang adil di semua aplikasi. Untuk mengonfigurasi batas bawah perlindungan memory.min yang dapat menyesuaikan sendiri pada daemon interaktif penting dan batas atas memory.high yang lebih ketat dan dikalibrasi workload pada setiap aplikasi dan layanan sistem, lihat Anggaran memori sistem.

  • Tidak adanya API kueri runtime: Di Android 17 dan yang lebih tinggi, aplikasi tidak dapat membuat kueri batas memori yang ditetapkan secara terprogram saat runtime. Batas platform standar ditentukan dengan margin yang besar sehingga aplikasi yang berperilaku baik dapat beroperasi tanpa batasan selama penggunaan normal.

  • Dinamika reclaim dan swap kernel: Saat proses aplikasi mendekati batas memory.high, kernel Linux mengarahkan reclaim memori secara khusus ke cgroup proses tersebut. Hal ini termasuk menghapus halaman yang didukung file yang tidak aktif dan menukar halaman anonim yang tidak aktif ke ZRAM, sehingga menjaga kelancaran sistem tanpa membebani memori global.

Perintah shell

Perintah am memory-limiter memungkinkan developer dan integrator sistem berinteraksi dengan layanan saat runtime untuk pengembangan, pengujian, dan proses debug:

am memory-limiter <SUB-COMMAND>

status

Subperintah status melaporkan status operasional dan metrik aktif Pembatas Memori:

adb shell am memory-limiter status

Berikut adalah contoh output:

Memory limiter
  enabled                  monitoring=true          ignored=none
  visibleMem=1948MB        visibleSwap=974MB
  notVisibleMem=974MB      notVisibleSwap=487MB
  started=36               watched=36               watch-failed=0
  events=0                 processes=36             process-hwm=36

Kolom utama dalam output mencakup:

monitoring
Menunjukkan apakah Pembatas Memori secara aktif memantau proses.
visibleMem dan notVisibleMem
Batas memori absolut yang dihitung (memory.high) yang saat ini diterapkan untuk setiap status visibilitas.
visibleSwap dan notVisibleSwap
Batas swap absolut yang dihitung (memory.swap.max) saat ini diterapkan untuk setiap status visibilitas.
events
Berapa kali proses melampaui batas yang ditetapkan.
processes
Jumlah proses yang dipantau saat ini.

ignore

Subperintah ignore mengecualikan UID tertentu atau semua proses dari pembatasan memori untuk sementara. Hal ini berguna untuk tolok ukur performa, pengujian stres, atau mendiagnosis perilaku memori:

# Ignore a specific UID
adb shell am memory-limiter ignore 10087
# Ignore all processes (temporarily disables limiting)
adb shell am memory-limiter ignore all
# Resume normal limiting operation
adb shell am memory-limiter ignore none

manual

Subperintah manual mengganti batas yang dihitung untuk proses tertentu berdasarkan ID proses (PID) dengan nilai absolut kustom dalam byte. Nilai harus berupa bilangan bulat, tetapi dapat menyertakan akhiran MB untuk menunjukkan MiB atau akhiran GB untuk menunjukkan GiB:

# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1073741824
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1024MB
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1GB
# Remove the manual override for PID 1234
adb shell am memory-limiter manual 1234 none

Penggantian manual hanya berlaku selama masa aktif instance proses tertentu tersebut. Jika proses dimulai ulang, proses tersebut akan kembali ke batas standar berdasarkan statusnya.

Penggantian manual tidak boleh melebihi batas sistem fisik.