Proses aplikasi di Android tidak ada secara terpisah. Aplikasi sering kali mengandalkan layanan yang disediakan oleh aplikasi lain atau sistem itu sendiri. Saat satu proses terhubung ke proses lain melalui Pengikatan Layanan, proses tersebut akan membuat dependensi yang berdampak besar pada cara framework Android mengelola memori.
Status proses dan skor OOM
Framework Android menggunakan Status Proses untuk melacak pentingnya setiap
proses yang sedang berjalan. Status ini kemudian digunakan oleh OomAdjuster untuk menetapkan nilai
Penyesuaian Skor OOM (oom_score_adj), mulai dari -1000 hingga 1000.
oom_score_adj yang lebih rendah berarti proses lebih penting dan cenderung tidak dihentikan oleh Low Memory Killer (LMK).
Status proses umum
Tabel berikut menunjukkan beberapa status proses yang paling umum dan nilai oom_score_adj yang biasanya. Untuk daftar lengkap dan terbaru, lihat
android.app.ActivityManager dan com.android.server.am.psc.Constants di
kode sumber Android.
| Status Proses (Singk.) | Deskripsi | oom_score_adj Standar |
|---|---|---|
| PER (Persisten) | Proses sistem yang harus selalu berjalan (misalnya, Telepon). | -800 |
| TOP | Proses yang saat ini berinteraksi dengan pengguna. | 0 |
| VIS (Terlihat) | Proses memiliki aktivitas yang terlihat (misalnya, di belakang dialog transparan). | 100 |
| PERC (Terlihat) | Proses latar belakang yang diketahui pengguna (misalnya, pemutaran musik). | 200 |
| FGS | Proses yang menghosting Layanan Latar Depan. | 0 hingga 200 (bervariasi) |
| BTOP (Bound Top) | Proses yang terikat oleh aplikasi TOP. | 100 |
| BFGS | Layanan Latar Depan Terikat (biasanya terikat sistem). | 0 |
| SEBELUMNYA (Sebelumnya) | Proses terakhir yang dilakukan pengguna sebelum proses saat ini. | 700 |
| DI-CACHE | Aplikasi latar belakang yang dapat dihentikan dengan aman. | 900 hingga 999 |
Dampak binding layanan
Saat proses klien (misalnya, aplikasi dalam status TOP) terikat ke layanan dalam
proses server, proses server sering kali mewarisi prioritas yang lebih tinggi. Hal ini
memastikan layanan tetap tersedia selama klien membutuhkannya.

Mengontrol pewarisan dengan tanda BIND
Pewarisan adalah perilaku default saat menggunakan Context.BIND_AUTO_CREATE.
Namun, developer dapat mengontrol pengaruh pengikatan terhadap
tingkat kepentingan proses target menggunakan berbagai flag di bindService().
Flag BIND utama untuk skor OOM
Tanda berikut paling relevan saat mengelola tekanan memori di seluruh sistem:
BIND_AUTO_CREATE: Flag yang paling umum. Hal ini memastikan proses layanan dimulai dan tetap aktif selama binding ada. Secara default, setelan ini juga meningkatkan prioritas proses server agar sesuai dengan klien.BIND_NOT_FOREGROUND: Mencegah proses layanan target dinaikkan ke prioritas penjadwalan latar depan (prioritas CPU). Namun, masih memungkinkan prioritas memori (oom_score_adj) ditingkatkan. Hal ini berguna untuk pekerjaan latar belakang yang tidak boleh bersaing dengan UI untuk siklus CPU, tetapi harus tetap dilindungi agar tidak dihentikan.BIND_WAIVE_PRIORITY: Flag yang sangat kuat yang menginstruksikan sistem untuk tidak memengaruhi prioritas penjadwalan atau pengelolaan memori dari proses target. Proses layanan akan dikelola seolah-olah merupakan proses latar belakang reguler dalam daftar LRU, sehingga memenuhi syarat untuk dihentikan karena kehabisan memori (OOM), meskipun saat terikat.BIND_ABOVE_CLIENT: Menunjukkan bahwa layanan lebih penting daripada aplikasi klien itu sendiri. Saat sistem perlu merebut kembali memori, sistem akan lebih memilih menghentikan aplikasi klien sebelum menghentikan layanan terikat. Metode ini "lebih kuat" daripadaBIND_AUTO_CREATEkarena memberikan lapisan perlindungan tambahan untuk layanan dengan mengorbankan klien.BIND_NOT_PERCEPTIBLE: Menurunkan kepentingan layanan target ke bawah tingkatPERCEPTIBLE, sehingga sistem dapat merebut kembali memorinya untuk menyediakan ruang bagi proses yang lebih penting dan dapat dirasakan pengguna.
Pengalaman langsung: mengamati efek pengikatan
Kita akan menggunakan aplikasi MemoryLab untuk menunjukkan cara pengikatan dari aplikasi
TOP memengaruhi status proses terpisah.
1. Meluncurkan MemoryLab
Perintah berikut meluncurkan aplikasi. Setelah terbuka, pastikan aplikasi tetap di latar depan (jangan tekan tombol Beranda atau beralih aplikasi dulu).
adb shell am start -n com.android.memorylab/.MainActivity
2. Mengidentifikasi proses
Periksa status proses sebelum mengikat. MemoryLab menjalankan UI utamanya dalam satu proses dan memiliki RemoteService yang berjalan dalam proses :remote.
adb shell dumpsys activity processes com.android.memorylab
Cuplikan contoh output:
Process OOM control (154 total, non-act at 7, non-svc at 7):
Proc #0: fg T/A/TOP LCMNFUATI t: 0 13470:com.android.memorylab/u0a417 (top-activity)
oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
state: cur=TOP set=TOP lastRss=0.00 lastCachedRss=0.00
Anda akan melihat proses utama com.android.memorylab dalam status TOP. Proses
:remote belum dimulai.
3. Binding pemicu
Kirim siaran ke aplikasi untuk memicu pengikatan layanan:
adb shell am broadcast -a com.android.memorylab.LEAK_BINDER
4. Mengamati status yang ditinggikan
Periksa kembali status proses:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
Cuplikan contoh output:
Proc # 1: vis F/ /BTOP ---NFUATI t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
state: cur=BTOP set=BTOP lastRss=0.00 lastCachedRss=0.00
Proses :remote kini berjalan dan dalam status BTOP (Bound TOP) dengan
oom_score_adj 100. Layanan ini jauh lebih terlindungi daripada layanan latar belakang biasa (yang akan berada di 500 atau lebih tinggi). Notasi
<=Proc{...} menunjukkan proses mana yang bertanggung jawab atas peningkatan prioritas ini.
5. Kirim ke latar belakang
Tekan tombol HOME di perangkat. Periksa kembali statusnya:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
Cuplikan contoh output:
Proc # 2: prev b/ /LAST --------I t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=0.00 lastCachedRss=0.00
Proc # 1: prev b/ /LAST --------I t: 0 13470:com.android.memorylab/u0a417 (previous)
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=209MB lastCachedRss=0.00
Sekarang kedua proses telah beralih ke status prioritas yang lebih rendah (PREV /
oom_score_adj 700), karena proses klien tidak lagi TOP. (Catatan:
LAST dalam dump status merujuk pada status internal LAST_ACTIVITY, yang
dipetakan ke PREV dalam ringkasan tingkat tinggi).
Menganalisis dengan procstats
Alat procstats memberikan tampilan historis dari status ini.
# View stats for MemoryLab over the last hour
adb shell dumpsys procstats --hours 1 com.android.memorylab
Cuplikan contoh output:
* com.android.memorylab / u0a417 / v37:
* Prc com.android.memorylab / u0a417 / v37:
TOTAL: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
Top: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
* Prc com.android.memorylab:remote / u0a417 / v37:
TOTAL: 0.19%
Bnd Top: 0.19%
Di sini, Bnd Top menunjukkan persentase waktu yang dihabiskan proses jarak jauh
untuk terikat oleh aplikasi dalam status TOP.
Merekam dan menganalisis binding dengan Perfetto
Meskipun dumpsys memberi Anda gambaran singkat, Perfetto memungkinkan Anda melihat momen
saat binding terjadi dan bagaimana skor OOM berubah secara real time.
1. Merekam aktivitas
Gunakan konfigurasi yang mencakup linux.process_stats dan kategori atrace am:
adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/service_bindings.perfetto-trace <<EOF
buffers: { size_kb: 65536 }
data_sources: {
config {
name: "linux.process_stats"
process_stats_config { proc_stats_poll_ms: 100 }
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config { ftrace_events: "am/am_proc_bound" }
}
}
duration_ms: 15000
EOF
2. Transisi skor OOM kueri
Dengan PerfettoSQL, Anda dapat melihat perubahan skor OOM proses jarak jauh relatif terhadap proses UI:
SELECT ts, p.name, value AS oom_score_adj
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
JOIN process p USING (upid)
WHERE p.name LIKE 'com.android.memorylab%'
AND t.name = 'oom_score_adj'
ORDER BY ts;
3. Mengidentifikasi peristiwa pengikatan
Untuk melihat secara tepat kapan dependensi binding dibuat dan proses mana yang memulainya, gunakan kueri ini:
SELECT
s.ts,
p.name AS process_name,
t.name AS thread_name,
s.name AS slice_name
FROM slice s
JOIN thread_track tt ON s.track_id = tt.id
JOIN thread t USING (utid)
JOIN process p USING (upid)
WHERE s.name LIKE 'bindService:{com.android.memorylab%';
Pengikatan sistem ke aplikasi
Sistem Android itu sendiri sering kali terikat ke layanan di aplikasi pihak ketiga untuk menyediakan fungsi inti. Tujuan dari pengikatan ini sering kali adalah pengurangan latensi. Dengan menjaga proses tetap aktif dan dalam memori, sistem menghindari overhead yang mahal dari "cold start" (memuat APK, menginisialisasi runtime, dan membuat objek Aplikasi) saat interaksi pengguna yang penting terjadi. Binding lain ada untuk mencegah cold start yang sering terjadi pada aplikasi yang perlu menangani aliran peristiwa latar belakang.
Berikut beberapa contoh dunia nyata yang dapat Anda amati di perangkat biasa:
VoiceInteractor
Pengguna mengharapkan asisten digital disematkan di OS ponsel mereka, agar dapat memanggilnya secara instan dengan kata kunci lisan atau gestur input cepat, dan interaksinya lancar dan mulus.
Saat pemicu asisten terjadi (seperti kata kunci "OK Google" di ponsel Google Pixel), asisten digital harus merespons secara instan. Untuk memastikan hal ini, system_server mempertahankan pengikatan permanen ke layanan interaksi suara yang dipilih oleh pengguna.

Jika Anda memeriksa status proses (misalnya, menggunakan dumpsys activity processes), Anda mungkin melihat proses seperti com.google.android.googlequicksearchbox:interactor dalam status BFGS (Layanan Latar Depan Terikat), yang tetap aktif karena terikat dari system_server (UID 1000).
NotificationListenerService
Untuk beberapa binding sistem ke aplikasi, tujuannya bukan latensi, melainkan mencegah cold start yang sering.
NotificationListenerService,
layanan yang menerima panggilan dari sistem saat notifikasi baru diposting
atau dihapus, adalah contoh utama. Pengguna smartphone biasa dapat menerima ratusan notifikasi sepanjang hari. Jika sistem melepaskan binding dari pemroses notifikasi, proses aplikasi tersebut kemungkinan akan masuk ke status yang di-cache dan dapat dihentikan oleh LMK.
Saat notifikasi berikutnya tiba - mungkin beberapa detik kemudian - sistem akan dipaksa untuk memulai ulang proses aplikasi dari awal hanya untuk mengirimkan peristiwa tersebut. Siklus penghentian dan cold start yang konstan ini akan menggunakan CPU dan baterai yang jauh lebih banyak daripada sekadar menjaga proses tetap terikat dan aktif di latar belakang.
"Layar -1" peluncur (feed berita)
Aplikasi Peluncur Modern biasanya menggabungkan fungsi navigasi inti (ikon dan widget layar utama) dengan feed berita yang tersedia di salah satu layar peluncur dan terintegrasi dengan lancar dengan UX Peluncur. Feed berita dapat disediakan oleh aplikasi lain. Misalnya, di Google Pixel, Peluncur terintegrasi dengan feed yang disediakan oleh aplikasi Google.
Saat Anda menggeser ke kiri di layar utama untuk melihat feed berita, transisinya harus lancar. Peluncur mencapai hal ini dengan mengikat ke antarmuka layanan di aplikasi yang menyediakan feed berita, dan mempertahankan pengikatan tersebut selama peluncur aktif. Hal ini membuat konten feed dirender dan siap di memori meskipun Anda tidak melihatnya.
Contoh umum lainnya
- Peluncur (HOME_APP_ADJ): Aplikasi peluncur (Home) memiliki slot khusus sendiri dalam daftar prioritas. Meskipun tidak selalu terikat oleh layanan, ID ini diberi
HOME_APP_ADJ(biasanya 600). Sistem lebih memilih untuk menjaga peluncur tetap aktif, karena pengguna sering kembali ke peluncur. Faktanya, sistem lebih memilih untuk menghentikan aplikasi yang digunakan sebelumnya (PREV_APP_ADJ = 700) daripada menghentikan peluncur, karena menghentikan peluncur akan menghasilkan pengalaman pengguna yang lambat saat keluar dari aplikasi karena pengguna harus menunggu peluncur dimulai dari awal. - Editor Metode Input (IME): Saat Anda mengetik, sistem akan terikat ke aplikasi keyboard pilihan Anda (misalnya, Gboard). Hal ini membuat proses keyboard dalam status yang lebih tinggi meskipun keyboard disembunyikan untuk sementara. Hal ini memastikan keyboard dapat muncul kembali secara instan saat Anda mengetuk kolom teks lain.
- Pembayaran NFC: Saat Anda mengetuk ponsel untuk membayar, sistem akan terikat ke layanan pembayaran NFC (misalnya, Google Wallet). Transaksi ini sering kali memiliki persyaratan real-time yang ketat dari terminal penjual. Jika aplikasi pembayaran harus melakukan cold start, transaksi dapat mengalami waktu tunggu habis dan gagal.
Kompromi dan penurunan performa
Meskipun pengikatan diperlukan untuk performa dan kebenaran, pengikatan memengaruhi kondisi memori sistem.
- Berkurangnya Fleksibilitas: Setiap proses terikat adalah proses yang tidak dapat dihentikan dengan mudah oleh LMK. Hal ini mengurangi "penyangga" proses yang di-cache yang dapat digunakan sistem untuk mengosongkan memori saat tertekan.
- Memperparah Masalah Performa: Jika terlalu banyak proses yang terikat, sistem mungkin tidak memiliki proses latar belakang yang dapat dihentikan. Saat tekanan memori meningkat, sistem akan "turun dari performa yang tinggi" lebih cepat, karena sistem dipaksa untuk menghentikan proses yang lebih penting atau meng-thrash cache halaman.
Antipola pengikatan layanan umum
Karena binding layanan secara langsung meningkatkan oom_score_adj, kesalahan siklus proses yang tidak terlalu terlihat dalam cara Anda mendapatkan atau menyusun binding dapat menyematkan sejumlah besar memori dalam status istimewa (BTOP, BFGS, atau PERC) selama berjam-jam. Waspadai
anti-pola umum ini saat mendesain atau mengaudit layanan terikat.
unbindService() yang terlupakan di klien yang aktif dalam waktu lama
Mengikat ke layanan dari singleton Application, pengelola latar belakang, atau
Activity yang memanggil bindService() di onStart() tanpa unbindService() yang cocok
di onStop() akan membocorkan ServiceConnection.
Selama binding tersebut tetap aktif, proses target akan mewarisi prioritas tinggi klien. Jika klien adalah komponen sistem persisten atau aplikasi latar depan, proses layanan terikat akan tetap disematkan di BFGS atau BTOP tanpa batas waktu (muncul mendekati 100% di procstats), sehingga mencegah LMK merebut kembali memorinya meskipun layanan benar-benar tidak aktif.
Solusi: Cakupan binding secara ketat ke siklus proses komponen yang
membutuhkannya, atau terapkan waktu tunggu tidak ada aktivitas yang memanggil unbindService() setelah
periode tidak ada aktivitas. Hindari pelepasan dan pengikatan ulang pada setiap panggilan RPC
individual, yang menyebabkan thrashing proses dan overhead penyiapan Binder berulang;
sebaliknya, gabungkan burst pekerjaan di belakang timer tidak ada aktivitas singkat (misalnya, 5 hingga
30 detik).
Menempatkan layanan terikat bersama dengan UI yang menggunakan banyak memori
Secara default, semua komponen dalam APK berjalan dalam proses yang sama. Jika aplikasi Anda
mengekspos layanan terikat ringan (seperti NotificationListenerService, penyedia
widget, atau layanan plugin yang terikat ke sistem atau peluncur) dalam
proses yang sama dengan Activity utama, seluruh proses akan mewarisi
status layanan yang lebih tinggi (BFGS atau PERC, biasanya oom_score_adj 200 atau
lebih rendah).
Saat pengguna membuka UI aplikasi Anda, proses akan mengalokasikan hierarki tampilan besar, bitmap yang didekode, dan buffer grafis. Saat pengguna keluar, proses tidak turun ke CACHED (oom_score_adj 900 atau lebih tinggi) karena pengikatan layanan aktif membuat proses tetap tinggi. Hal ini menyebabkan dua masalah yang saling terkait:
- Tidak ada pemadatan memori latar belakang:
CachedAppOptimizersistem hanya memadatkan proses setelah proses tersebut memasuki statusCACHED. - Tidak ada pemangkasan memori LRU yang di-cache atau reklamasi LMK: Sistem tidak memberikan callback pemangkasan latar belakang yang terkait dengan daftar LRU yang di-cache (
TRIM_MEMORY_BACKGROUNDdan yang lebih tinggi) saat pengikatan layanan menahan proses dalam status yang lebih tinggi. Jika aplikasi Anda tidak merilis resource UI secara eksplisit diTRIM_MEMORY_UI_HIDDENatauActivity.onStop(), alokasi UI puncak akan tetap disematkan di RAM pada skor OOM yang diizinkan, sehingga LMK tidak dapat dengan mudah mereklamasi resource tersebut.
Solusi: Keluarkan cache UI, bitmap yang didekode, dan referensi tampilan secara eksplisit
saat UI Anda berhenti terlihat, menggunakan Activity.onStop(),
ComponentCallbacks2.onTrimMemory(TRIM_MEMORY_UI_HIDDEN),
Application.ActivityLifecycleCallbacks, atau
ProcessLifecycleOwner. Atau, pindahkan layanan yang selalu terikat ke proses terpisah dan ringan menggunakan atribut manifes android:process sehingga sistem dapat memindahkan proses UI utama Anda ke status CACHED untuk memadatkan atau merebut kembali memorinya secara independen.
Menghilangkan tanda pengabaian prioritas
Memanggil bindService() dengan BIND_AUTO_CREATE saja akan mentransfer
penjadwalan lengkap dan prioritas memori penelepon ke layanan target. Saat aplikasi latar depan terikat ke layanan analisis, logging, atau pengambilan data latar belakang hanya menggunakan BIND_AUTO_CREATE, aplikasi tersebut secara tidak sengaja mempromosikan pekerja latar belakang tersebut ke BTOP.
Solusi: Saat mengikat ke layanan tambahan atau layanan terbaik yang tidak memerlukan
tingkat perlindungan yang sama dengan UI latar depan, gabungkan BIND_AUTO_CREATE dengan
BIND_WAIVE_PRIORITY, BIND_NOT_FOREGROUND, atau BIND_NOT_PERCEPTIBLE sehingga
sistem masih dapat mengelola proses target pada daftar LRU yang di-cache.
← Lokalitas | ↑ Atas | Di seluruh sistem →