Pembatas Memori

Android 17 dan yang lebih tinggi menyertakan Pembatas Memori, yaitu layanan sistem yang memantau dan membatasi penggunaan memori proses aplikasi menggunakan cgroup v2 Linux. Pembatas Memori mencegah aplikasi individual mengonsumsi memori sistem secara tidak proporsional, yang mengurangi tekanan memori secara keseluruhan dan mencegah penghentian agresif proses penting di latar depan dan dalam cache karena memori rendah.

Mekanisme

Pembatas Memori terintegrasi dengan Layanan Pengelola Aktivitas (AMS) untuk melacak peristiwa siklus proses dan perubahan status proses. 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 terlampaui, proses akan dibatasi dan kernel akan mencoba merebut 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 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 penggantian dan penghapusan halaman ini, aplikasi mungkin mengalami pembatasan eksekusi sementara, tetapi aplikasi akan 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 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 yang tidak terlihat: Proses yang melakukan pekerjaan di latar belakang tanpa menampilkan UI (seperti layanan latar belakang atau penerima siaran). Karena tidak merender komponen UI, fungsi 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 proses melampaui batas memory.high yang ditetapkan, Pembatas Memori akan mendeteksi peristiwa tersebut dan dapat memicu tindakan diagnostik, seperti merekam profil memori atau mencatat anomali ke statsd.

Konfigurasi

Di Android 17 dan yang lebih tinggi, Pembatas Memori menyediakan file konfigurasi default platform standar di partisi sistem, sekaligus mendukung penggantian khusus perangkat opsional di partisi vendor:

  • Konfigurasi default sistem: /system/etc/memory-limiter-config.xml
  • Penggantian vendor (opsional): /vendor/etc/memory-limiter-config.xml

Pembatas Memori memeriksa /vendor/etc/memory-limiter-config.xml terlebih dahulu. Jika ada, konfigurasi vendor akan digunakan; jika tidak, konfigurasi akan melakukan fallback ke konfigurasi sistem default di /system/etc/memory-limiter-config.xml.

Format XML

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

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <!-- RAM minimums account for MemTotal excluding carve-outs. -->
    <limitSet>
      <!-- Limits for 16GB RAM device (MemTotal >= 13GiB): 10G/5G/5G/5G -->
      <minimumRequiredMemTotal>13312</minimumRequiredMemTotal>
      <memVisible>10240</memVisible>
      <memNotVisible>5120</memNotVisible>
      <swapVisible>5120</swapVisible>
      <swapNotVisible>5120</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 12GB RAM device (MemTotal >= 10GiB): 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>10240</minimumRequiredMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 8GB RAM device (MemTotal >= 6.5GiB): 5G/3G/3G/3G -->
      <minimumRequiredMemTotal>6656</minimumRequiredMemTotal>
      <memVisible>5120</memVisible>
      <memNotVisible>3072</memNotVisible>
      <swapVisible>3072</swapVisible>
      <swapNotVisible>3072</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 6GB RAM device (MemTotal >= 4.5GiB): 4G/2G/2G/2G -->
      <minimumRequiredMemTotal>4608</minimumRequiredMemTotal>
      <memVisible>4096</memVisible>
      <memNotVisible>2048</memNotVisible>
      <swapVisible>2048</swapVisible>
      <swapNotVisible>2048</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 4GB RAM device (MemTotal >= 3GiB): 2G/1G/1G/1G -->
      <minimumRequiredMemTotal>3072</minimumRequiredMemTotal>
      <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

Sistem minimum MemTotal (dalam MiB) yang diperlukan agar set batas ini dapat diterapkan. Layanan mengevaluasi hal ini terhadap total memori yang tersedia yang dilaporkan oleh kernel di /proc/meminfo.

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

Karena MemTotal lebih rendah daripada DRAM fisik yang diiklankan perangkat, nilai minimum minimumRequiredMemTotal mencakup margin untuk alokasi ini. Misalnya, konfigurasi yang menargetkan perangkat 16 GB menentukan minimumRequiredMemTotal sebesar 13312 (13 GiB), bukan 16384 (16 GiB), dan tingkat untuk perangkat 12 GB menentukan 10240 (10 GiB). Hal ini memastikan bahwa setiap perangkat sesuai dengan tingkat yang dimaksudkan, terlepas dari variasi alokasi tingkat board.

memVisible

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

memNotVisible

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

swapVisible

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

swapNotVisible

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

Batas platform standar

Di Android 17 dan yang lebih baru, platform menentukan batas memori dan swap standar di /system/etc/memory-limiter-config.xml di seluruh tingkat RAM fisik umum:

Menargetkan RAM fisik Minimum yang diperlukan
MemTotal
(minimumRequiredMemTotal)
Batas memori yang terlihat
(memVisible)
Batas memori tidak terlihat
(memNotVisible)
Batas penukaran yang terlihat
(swapVisible)
Batas penukaran yang tidak terlihat
(swapNotVisible)
16 GB 13.312 MiB (13 GiB) 10.240 MiB (10 GiB) 5.120 MiB (5 GiB) 5.120 MiB (5 GiB) 5.120 MiB (5 GiB)
12 GB 10.240 MiB (10 GiB) 8.192 MiB (8 GiB) 4.096 MiB (4 GiB) 4.096 MiB (4 GiB) 4.096 MiB (4 GiB)
8 GB 6.656 MiB (6,5 GiB) 5.120 MiB (5 GiB) 3.072 MiB (3 GiB) 3.072 MiB (3 GiB) 3.072 MiB (3 GiB)
6 GB 4.608 MiB (4,5 GiB) 4.096 MiB (4 GiB) 2.048 MiB (2 GiB) 2.048 MiB (2 GiB) 2.048 MiB (2 GiB)
4 GB 3.072 MiB (3 GiB) 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 prematur.

  • 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: Dialokasikan 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 yang telah diinstal sebelumnya. Pembatas Memori tidak mendukung daftar yang diizinkan untuk mengecualikan aplikasi tertentu, sehingga memastikan tata kelola memori yang adil di semua aplikasi.

  • Tidak adanya API kueri runtime: Di Android 17 dan yang lebih tinggi, aplikasi tidak dapat mengkueri 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 swap dan pelepasan kernel: Saat proses aplikasi mendekati batas memory.high, kernel Linux mengarahkan pelepasan memori secara khusus ke cgroup proses tersebut. Hal ini mencakup penghapusan halaman yang didukung file yang tidak aktif dan menukar halaman anonim dingin ke ZRAM, sehingga menjaga kelancaran sistem tanpa memaksakan tekanan 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

Sub-perintah status melaporkan status operasional dan metrik aktif Pembatas Memori:

adb shell am memory-limiter status

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 sedang aktif memantau proses.
visibleMem dan notVisibleMem
Batas memori absolut yang dihitung (memory.high) saat ini diterapkan untuk setiap status visibilitas.
visibleSwap dan notVisibleSwap
Batas penukaran absolut yang dihitung (memory.swap.max) yang saat ini diterapkan untuk setiap status visibilitas.
events
Jumlah proses yang telah melampaui batas yang ditetapkan.
processes
Jumlah proses yang dipantau saat ini.

abaikan

Sub-perintah ignore mengecualikan UID tertentu atau semua proses dari pembatasan memori untuk sementara. Hal ini berguna untuk tolok ukur performa, pengujian tekanan, 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

Sub-perintah manual menggantikan 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 akan kembali ke batas standar berdasarkan statusnya.

Penggantian manual tidak dapat melampaui batas sistem fisik.