Banyak aplikasi melakukan pekerjaan yang sah saat UI-nya tidak lagi terlihat, seperti
mendownload paket aset besar, menyinkronkan database lokal, melakukan streaming audio,
merekam latihan olahraga, atau mempertahankan sesi perangkat yang terhubung. Saat
pekerjaan latar belakang ini berjalan di dalam proses OS yang sama dengan UI latar depan dan
mesin grafis, seluruh proses tetap berada pada tingkat kepentingan yang lebih tinggi
(oom_score_adj antara 0 dan 250) bersama dengan semua memori yang
dialokasikan UI.
Halaman ini menjelaskan alasan hal tersebut merugikan aplikasi Anda sendiri serta perangkat lainnya, cara memindahkan pekerjaan latar belakang ke proses ringan khusus menggunakan android:process, dan cara memverifikasi penghematan memori menggunakan adb shell dan Perfetto.
Alasan pekerjaan satu proses mempertahankan memori UI
Android mengelola memori dan penghentian proses pada tingkat perincian proses
OS (pid), bukan komponen individual (Activity, Service, atau
BroadcastReceiver). Activity Manager (OomAdjuster) menetapkan satu nilai oom_score_adj
untuk setiap proses yang mencerminkan komponen aktif atau binding masuk
yang paling penting dalam proses tersebut:
- Saat pengguna berinteraksi dengan
ActivityAnda, proses akan berjalan dalam statusTOP(oom_score_adj = 0). - Saat pengguna keluar dan aplikasi Anda tidak memiliki komponen latar belakang
yang aktif, proses akan berpindah ke bucket
PREV(oom_score_adj = 700) atauCACHED(oom_score_adj >= 900). Dalam bucket yang di-cache, platform membekukan proses dengan freezer cgroup v2, memadatkan memorinya denganCachedAppOptimizer, dan memungkinkanlmkdmenghentikan proses terlebih dahulu di bawah tekanan memori. - Namun, jika proses yang sama juga menjalankan layanan latar depan (seperti
jenis
dataSync,mediaPlayback,connectedDevice, ataulocation, dioom_score_adj = 200) atau menghosting layanan yang terikat dengan sistem atau klien penting lainnya, seluruh proses akan tetap berada pada prioritas yang ditingkatkan tersebut bahkan setelahActivitydihentikan.
Saat proses UI yang berat tetap berada di oom_score_adj = 200, beberapa kategori memori
yang besar tetap berada di memori:
Activitydihentikan dan hierarki tampilan: Kecuali jikaActivitydiselesaikan secara eksplisit,Window, hierarki tampilan, struktur tata letak, dan status tampilannya tetap dapat dijangkau di heap Java saat pengguna berada di aplikasi lain.- Konteks grafis native dan alokasi GPU:
HardwareRendererstandar mempertahankan konteks dan cache GPU-nya, sedangkanActivityyang dihentikan berada dalam proses yang tidak di-cache. Aplikasi dan game engine yang membuat konteks Vulkan (VkDevice,VkSwapchainKHR, kumpulan deskriptor, cache pipeline) atau OpenGL ES (EGLContext, tekstur, buffer vertex) sendiri juga mempertahankan struktur driver, program shader, dan buffer grafis, kecuali jika engine secara eksplisit menghapus perangkat grafis saat dihentikan. - Fragmentasi heap dan overhead runtime: Meskipun aplikasi merilis
cache di
onTrimMemory, halaman pengalokasi native yang terisi sebagian, halaman copy-on-write Zygote yang kotor, library bersama yang dimuat (.so), dan metadata runtime tetap berada di memori pribadi proses. Karena prosesnya berada di atas batas yang di-cache (oom_score_adj < 900), platform tidak akan membekukannya atau menjalankan pemadatan aplikasi yang di-cache. Untuk melihat lebih dekat efek ini dengan layanan terikat, lihat Menempatkan layanan terikat bersama UI yang menggunakan banyak memori.
Cara proses latar belakang yang efisien melindungi aplikasi Anda
Menyimpan memori berukuran latar depan dalam status latar belakang akan membahayakan pekerjaan latar belakang Anda sendiri:
- Batas memori latar belakang lebih ketat daripada batas latar depan. Di Android 17 dan yang lebih baru, Pembatas Memori menerapkan batas memori tidak terlihat yang lebih kecil ke aplikasi Anda saat tidak ada prosesnya yang menampilkan UI yang terlihat, termasuk saat layanan latar depan berjalan. Batas ini mencakup semua proses aplikasi Anda secara bersamaan. Jika proses yang menjalankan layanan latar depan Anda masih menyimpan UI dan memori grafisnya, memori tersebut akan dihitung terhadap batas yang lebih kecil. Saat aplikasi Anda melebihi batas, kernel akan membatasinya saat mengklaim kembali halamannya, yang akan memperlambat download, sinkronisasi, atau pemutaran yang sedang berjalan. Jika aplikasi Anda terus mengalokasikan setelah swap habis, sistem akan menghentikannya. Untuk memeriksa apakah aplikasi Anda terpengaruh, lihat Batas memori aplikasi.
- Proses yang lebih besar akan dihentikan terlebih dahulu saat terjadi tekanan memori. Saat
lmkdharus mengosongkan memori dan dikonfigurasi untuk memilih proses terberat dalam bucket kepentingan (ro.lmk.kill_heaviest_task), proses layanan latar depan yang juga menyimpan ratusan MB memori UI akan dihentikan sebelum proses yang lebih kecil dengan kepentingan yang sama, dan pekerjaan latar belakang Anda akan berhenti bersamanya. Lihat interaksi kswapd dan lmkd. - Status UI yang di-cache dapat dibekukan, dipadatkan, dan ditulis kembali ke flash. Dengan mengizinkan status UI latar depan Anda berpindah ke proses yang di-cache, OS dapat membekukan proses, memadatkan memorinya ke dalam zRAM, dan menulis kembali halaman dinginnya ke penyimpanan flash. Jejak memori residennya menyusut sementara status UI Anda tetap utuh, sehingga memberikan peluang terbaik bagi pekerjaan latar belakang dan UI yang di-cache untuk bertahan hingga pengguna kembali.
- Anggaran memori per proses menjadi praktis. Proses yang hanya menjalankan pekerjaan latar belakang memiliki set kerja yang kecil dan dapat diprediksi, sehingga Anda dapat memberinya anggaran memori yang ketat tanpa membatasi UI Anda.
Menjalankan proses kedua mungkin terlihat seperti meningkatkan total jejak memori aplikasi Anda, karena runtime kedua memiliki biaya dasar pengukuran yang kecil. Perbandingan tersebut hanya berlaku jika satu proses dapat sepenuhnya mengosongkan semua status UI dan grafisnya setiap kali beralih ke pekerjaan latar belakang, yang tidak dapat dilakukan oleh aplikasi dan toolkit UI dengan andal dalam praktiknya. Membiarkan OS membekukan, memadatkan, dan menulis kembali proses UI yang di-cache secara terpisah akan menggunakan lebih sedikit memori fisik dalam kasus umum, menjaga aplikasi Anda tetap dalam batas tidak terlihat, dan mengurangi penghentian karena memori rendah untuk aplikasi Anda dan di seluruh perangkat.
Mengisolasi pekerjaan latar belakang dalam proses khusus
Untuk menghilangkan residensi UI dan grafis selama pekerjaan latar belakang, jalankan komponen latar belakang yang berjalan lama dalam proses ringan khusus sambil mempertahankan UI dan mesin grafis Anda dalam proses utama:
| Proses | Deklarasi manifes | Komponen yang dihosting | Status saat pengguna keluar dari UI selama pekerjaan latar belakang |
|---|---|---|---|
| Proses UI utama | Default (com.example.app) |
Activity, tampilan UI, cache gambar, perender Vulkan atau OpenGL ES, mesin audio dan scene
|
Turun ke PREV, lalu CACHED
(oom_score_adj >= 900). Dibekukan, dipadatkan, dan ditulis
kembali ke flash.
|
| Proses worker latar belakang | android:process=":bg" |
Service latar depan, downloader aset latar belakang, worker
sinkronisasi, atau pengelola perangkat terhubung
|
Berjalan di FGS (oom_score_adj = 200) hanya dengan
heap dan kode worker itu sendiri, serta tanpa tampilan UI atau konteks GPU.
|
Mendeklarasikan anggaran proses dan memori
Tetapkan Service latar belakang Anda ke subproses pribadi dengan menetapkan
android:process=":bg" di AndroidManifest.xml. Titik dua di awal (:)
membuat proses pribadi yang dicakup dalam UID aplikasi Anda.
Di Android 17 QPR2 (API level 37.2) dan yang lebih tinggi, gabungkan pemisahan proses dengan
anggaran memori aplikasi per proses di dalam
blok <processes> sehingga sistem operasi menerapkan batas set kerja yang ketat
pada worker latar belakang tanpa membatasi proses UI latar depan
Anda:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name=".HeavyApplication"
android:label="@string/app_name">
<!-- App-wide budgets that cover every process, including :bg -->
<memory-budget android:maxMb="512" />
<memory-budget
android:maxMb="128"
android:state="background" />
<processes>
<!-- Tight budget for the headless background worker process -->
<process android:process=":bg">
<memory-budget android:maxMb="32" />
</process>
</processes>
<activity
android:name=".MainActivity"
android:exported="true" />
<service
android:name=".AssetDownloadService"
android:process=":bg"
android:foregroundServiceType="dataSync"
android:exported="false" />
</application>
</manifest>
Penggunaan memori di :bg dihitung terhadap anggarannya sendiri dan anggaran
seluruh aplikasi. Pada perangkat yang menjalankan versi sebelum Android 17 QPR2, sistem
akan mengabaikan <memory-budget>, sedangkan android:process=":bg" berfungsi di semua level
API.
Inisialisasi gate di Application.onCreate
Android membuat instance class Application Anda dan memanggil Application.onCreate
di setiap proses yang dihasilkan untuk paket Anda. Kesalahan umum saat mengadopsi
android:process=":bg" adalah membiarkan toolkit UI yang berat, kumpulan pemuatan gambar,
Analytics SDK, atau inisialisasi mesin native (System.loadLibrary) di dalam
metode Application.onCreate yang tidak terlindungi. Tindakan ini akan meningkatkan proses :bg
dengan jejak dasar pengukuran yang sama dengan yang ingin Anda hindari.
Periksa Application.getProcessName, yang tersedia
di Android 9 (level API 28) dan yang lebih tinggi, di dalam onCreate dan hanya lakukan inisialisasi
dependensi yang diperlukan oleh proses saat ini:
Kotlin
class HeavyApplication : Application() {
override fun onCreate() {
super.onCreate()
val processName = Application.getProcessName()
if (processName != null && processName.endsWith(BG_PROCESS_SUFFIX)) {
initBackgroundWorkerProcess()
return
}
initMainUiProcess()
}
private fun initBackgroundWorkerProcess() {
// Initialize only lightweight HTTP, storage, and sync primitives.
// Avoid loading native rendering libraries or allocating UI caches.
}
private fun initMainUiProcess() {
// Initialize UI frameworks, image caches, and native engines.
System.loadLibrary("heavy_engine_jni")
}
companion object {
private const val BG_PROCESS_SUFFIX = ":bg"
}
}
Java
public final class HeavyApplication extends Application {
private static final String BG_PROCESS_SUFFIX = ":bg";
@Override
public void onCreate() {
super.onCreate();
String processName = Application.getProcessName();
if (processName != null && processName.endsWith(BG_PROCESS_SUFFIX)) {
initBackgroundWorkerProcess();
return;
}
initMainUiProcess();
}
private void initBackgroundWorkerProcess() {
// Initialize only lightweight HTTP, storage, and sync primitives.
// Avoid loading native rendering libraries or allocating UI caches.
}
private void initMainUiProcess() {
// Initialize UI frameworks, image caches, and native engines.
System.loadLibrary("heavy_engine_jni");
}
}
Library yang melakukan inisialisasi melalui penyedia konten, seperti Jetpack App
Startup, hanya melakukan inisialisasi dalam proses utama, karena penyedia konten
yang dideklarasikan tanpa android:process berjalan dalam proses utama. Jika kode di :bg
bergantung pada library tersebut, lakukan inisialisasi secara eksplisit di
initBackgroundWorkerProcess.
Jika Anda membangun dengan game engine seperti Unity, terapkan layanan latar belakang
dalam library atau plugin Android biasa yang ditulis dalam Java atau Kotlin yang tidak
mereferensikan class engine seperti UnityPlayer. Proses :bg kemudian tidak pernah
memuat library native mesin. Untuk mengonfirmasi, pastikan
adb shell cat /proc/<pid>/maps untuk proses :bg tidak mencantumkan
libunity.so atau libil2cpp.so.
Berkomunikasi tanpa menyematkan proses UI
Saat pengguna membuka MainActivity saat AssetDownloadService berjalan di
:bg, UI sering kali perlu menampilkan progres download langsung. Kepentingan proses
mengalir dari klien ke proses yang menghosting layanan atau penyedia konten
yang digunakannya, sehingga arah setiap dependensi menjadi penting:
- Binding UI ke worker aman. Saat
MainActivitymengikat keAssetDownloadService, sistem akan meningkatkan:bgke tingkat kepentingan UI yang terlihat. Saat pengguna keluar, proses UI akan di-cache dan binding tidak lagi meningkatkan apa pun. - Worker yang bergantung pada proses UI tidak aman. Jika kode di
:bgterikat ke layanan atau mengkueri penyedia konten yang berjalan dalam proses utama, sistem akan meningkatkan proses utama ke tingkat kepentingan yang lebih tinggi dari worker, dan memori UI akan tetap disematkan lagi. Minta UI mendaftarkan callback dengan worker, sepertiMessengeratau antarmuka callback AIDL. Meneruskan objek binder sebagai callback tidak mengubah tingkat kepentingan salah satu proses.
Batalkan pendaftaran callback sebelum Anda membatalkan binding, sehingga worker tidak pernah memanggil proses UI setelah sistem membekukannya. Contoh berikut mengikat ke worker hanya saat UI terlihat:
Kotlin
class MainActivity : Activity() {
private var downloadService: IBinder? = null
private val downloadConnection = object : ServiceConnection {
override fun onServiceConnected(
name: ComponentName,
service: IBinder
) {
downloadService = service
// Register a Messenger or AIDL callback for progress updates.
}
override fun onServiceDisconnected(name: ComponentName) {
// The binding stays active and reconnects if the worker restarts.
downloadService = null
}
}
override fun onStart() {
super.onStart()
val intent = Intent(this, AssetDownloadService::class.java)
bindService(intent, downloadConnection, Context.BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
if (downloadService != null) {
// Unregister the progress callback here, before unbinding.
downloadService = null
}
// Unbind the ServiceConnection even if onServiceConnected hasn't run
// yet.
unbindService(downloadConnection)
}
}
Java
public final class MainActivity extends Activity {
private IBinder downloadService;
private final ServiceConnection downloadConnection =
new ServiceConnection() {
@Override
public void onServiceConnected(
ComponentName name, IBinder service) {
downloadService = service;
// Register a Messenger or AIDL callback for progress
// updates.
}
@Override
public void onServiceDisconnected(ComponentName name) {
// The binding stays active and reconnects if the worker
// restarts.
downloadService = null;
}
};
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, AssetDownloadService.class);
bindService(intent, downloadConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (downloadService != null) {
// Unregister the progress callback here, before unbinding.
downloadService = null;
}
// Unbind the ServiceConnection even if onServiceConnected hasn't run
// yet.
unbindService(downloadConnection);
}
}
Untuk mengetahui informasi selengkapnya tentang pengaruh flag binding terhadap oom_score_adj di seluruh proses, lihat
Pengikatan layanan dan status proses.
Mengoordinasikan status bersama di disk dengan aman
Karena proses utama dan :bg berjalan di ruang alamat terpisah dengan runtime dan deskriptor file terpisah:
- SQLite dan Room: Gunakan write-ahead logging (mode jurnal default di Room di sebagian besar perangkat) sehingga kedua proses dapat membaca dan menulis database secara serentak. Jangan panggil
enableMultiInstanceInvalidationdari:bg. Room menghosting layanan invalidasinya di proses utama, sehingga worker akan mengikat ke proses utama dan mempertahankan memori UI pada tingkat kepentingan worker yang lebih tinggi. Sebagai gantinya, minta pekerja melaporkan perubahan melalui callback yang didaftarkan UI, dan minta UI mengkueri ulang database saat dimulai. - Preferensi: Jangan bagikan
SharedPreferencesdi seluruh proses. Gunakan DataStore dalam kode multiproses atau teruskan status secara eksplisit melalui IPC. - File aset: Tulis paket aset yang didownload ke file staging di
:bg, panggilfdatasync, laluposix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)di:bgsetelah menulis (seperti yang ditunjukkan dalam Mengembalikan halaman memori ke OS), dan ganti nama file secara atomik ke tempatnya. Biarkan UI mengambil hasilnya saat dimulai dan terikat ke worker, daripada memanggil proses UI yang mungkin dibekukan.
Mengamati efek di shell adb
Anda dapat memverifikasi bahwa pemisahan proses latar depan dan proses latar belakang mengisolasi penggunaan memori yang meningkat dengan memeriksa status proses Activity Manager dan
dumpsys meminfo setelah membuka Layar utama. Contoh output di
bagian ini berasal dari aplikasi contoh MemoryLab, yang menjalankan alokasi native 64 MB
yang sama dalam proses UI-nya di kedua konfigurasi dan menghosting layanan latar depan
terpisah dalam proses :remote.
1. Membandingkan status proses dan skor OOM
Mulai workload latar belakang, tekan tombol Layar utama agar Activity berhenti,
dan buat kueri Activity Manager:
adb shell dumpsys activity processes com.example.app | grep -E "Proc #|oom:|state:"
Dalam arsitektur proses tunggal, proses utama tetap ditingkatkan meskipun
Activity-nya dihentikan. Selama sekitar 15 detik setelah pengguna keluar, Activity
Manager mempertahankan proses yang menjalankan layanan latar depan di oom_score_adj = 50
(fg-service-act), lalu menurunkannya ke 200 (fg-service). Output berikut
diambil 20 detik setelah menekan Beranda:
Proc #1: prcp F/S/FGS ---NFUATI t: 0 13794:com.android.memorylab/u0a284 (fg-service)
oom: max=1001 curRaw=200 setRaw=200 cur=200 set=200
state: cur=FGS set=FGS lastRss=0.00 lastCachedRss=0.00
Dalam arsitektur proses terpisah, hanya proses worker yang tetap berada di
oom_score_adj = 200, sedangkan proses UI utama turun ke PREV
(oom_score_adj = 700) dan kemudian ke bucket yang di-cache
(oom_score_adj >= 900):
Proc #3: prcp F/S/FGS ---NFUATI t: 0 13544:com.android.memorylab:remote/u0a284 (fg-service)
oom: max=1001 curRaw=200 setRaw=200 cur=200 set=200
state: cur=FGS set=FGS lastRss=0.00 lastCachedRss=0.00
Proc #1: prev b/ /LAST -------TI t: 0 13312:com.android.memorylab/u0a284 (previous)
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=0.00 lastCachedRss=0.00
Setelah waktu tunggu aplikasi sebelumnya berakhir, proses utama akan berpindah ke bucket
yang di-cache (cch, oom_score_adj = 900, previous-expired) dan kehilangan semua
kemampuan prosesnya (---------), termasuk waktu CPU implisit (I). Pada saat itu,
sistem akan membekukannya dan dapat memadatkan atau mengklaimnya kembali kapan saja tanpa
mengganggu proses worker.
2. Membandingkan dumpsys meminfo di berbagai proses
Bandingkan ringkasan dumpsys meminfo dari worker yang ditingkatkan
dengan proses UI:
adb shell dumpsys meminfo com.example.app:bg
adb shell dumpsys meminfo com.example.app
Contoh output App Summary untuk proses worker MemoryLab di
oom_score_adj = 200:
App Summary
Pss(KB) Rss(KB)
------ ------
Java Heap: 380 13840
Native Heap: 1548 2832
Code: 132 55816
Stack: 200 208
Graphics: 0 0
Private Other: 496
System: 1926
Unknown: 4168
TOTAL PSS: 4682 TOTAL RSS: 76864 TOTAL SWAP PSS: 441
Contoh output App Summary untuk proses UI MemoryLab di
oom_score_adj = 700, yang menyimpan alokasi native 64 MB di
Private Other:
App Summary
Pss(KB) Rss(KB)
------ ------
Java Heap: 1316 19816
Native Heap: 30408 31596
Code: 3148 115796
Stack: 656 664
Graphics: 0 0
Private Other: 67044
System: 13687
Unknown: 71092
TOTAL PSS: 116259 TOTAL RSS: 238964 TOTAL SWAP PSS: 259
Proses worker memerlukan PSS kurang dari 5 MB, karena proses ini berbagi sebagian besar
kode dan halaman runtime-nya dengan Zygote. Dalam aplikasi yang merender dengan Vulkan atau OpenGL ES, baris Graphics dari proses UI juga menyertakan memori GPU.
Contoh ini diambil di perangkat virtual Cuttlefish dengan rendering
software, sehingga Graphics adalah 0 di kedua proses.
3. Memeriksa akuntansi cgroup per proses
Setiap proses di bawah UID Anda memiliki direktori cgroup v2 sendiri di dalam cgroup
induk untuk aplikasi Anda. Perintah berikut mencantumkan oom_score_adj,
memory.current, dan memory.high di seluruh aplikasi untuk setiap proses
aplikasi Anda:
adb shell '
for PID in $(pidof com.example.app com.example.app:bg); do
CG=/sys/fs/cgroup$(sed -n "s/^0:://p" /proc/$PID/cgroup)
echo "pid=$PID ($(tr -d "\0" < /proc/$PID/cmdline))" \
"adj=$(cat /proc/$PID/oom_score_adj)" \
"memory.current=$(cat $CG/memory.current)" \
"app.memory.high=$(cat ${CG%/*}/memory.high)"
done
'
Contoh output untuk MemoryLab setelah menekan Beranda:
pid=15301 (com.android.memorylab) adj=700 memory.current=103260160 app.memory.high=966787072
pid=16518 (com.android.memorylab:remote) adj=200 memory.current=3608576 app.memory.high=966787072
Proses worker dikenai biaya kurang dari 4 MB, sedangkan proses UI dikenai biaya sekitar 98 MB. Setiap proses memiliki memory.current-nya sendiri, tetapi
Pembatas Memori menetapkan batasnya pada cgroup induk yang berisi semua proses
aplikasi Anda. Kedua baris menampilkan app.memory.high yang sama, yaitu 966.787.072 byte,
yang merupakan batas tidak terlihat sebesar 922 MB dalam output berikut.
Untuk melihat batas terlihat dan tidak terlihat yang diterapkan oleh Pembatas Memori pada perangkat, jalankan perintah berikut:
adb shell am memory-limiter status
Contoh output dari perangkat dengan RAM 4 GB, dengan batas tidak terlihat adalah setengah dari batas terlihat:
Memory limiter
enabled limits=true killing=true ignored=none
visible: memHigh=1843MB memMax=2048MB swapMax=1024MB
not-visible: memHigh=922MB memMax=1024MB swapMax=1024MB
Mengamati efek di Perfetto
Perfetto memungkinkan Anda memvisualisasikan linimasa oom_score_adj dan RSS di kedua
proses saat pengguna berpindah dari UI latar depan ke Layar utama saat
pekerjaan latar belakang berlanjut.
1. Merekam aktivitas
Rekam rekaman aktivitas berdurasi 15 detik yang menangkap penghitung memori proses, memori GPU, dan
perubahan oom_score_adj saat memulai tugas latar belakang di aplikasi Anda dan
membuka Layar utama:
adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/process-splitting.perfetto-trace <<'EOF'
buffers: {
size_kb: 32768
fill_policy: DISCARD
}
data_sources: {
config {
name: "linux.process_stats"
process_stats_config {
scan_all_processes_on_start: true
proc_stats_poll_ms: 250
}
}
}
data_sources: {
config {
name: "android.gpu.memory"
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "oom/oom_score_adj_update"
ftrace_events: "gpu_mem/gpu_mem_total"
}
}
}
duration_ms: 15000
EOF
adb pull /data/misc/perfetto-traces/process-splitting.perfetto-trace
2. Memeriksa jalur proses di UI Perfetto
Buka rekaman aktivitas di Perfetto UI dan luaskan grup proses
untuk com.example.app dan com.example.app:bg:
- Sematkan trek
oom_score_adjdanmem.rss.anonuntuk kedua proses agar muncul berdampingan di bagian atas linimasa. - Temukan stempel waktu saat pengguna menekan Layar utama:
- Dalam proses worker,
oom_score_adjtetap di200danmem.rss.anontetap datar dan kecil. - Dalam proses UI,
oom_score_adjnaik dari0ke200, tetap di sana selama sekitar satu detik saatActivityberhenti, lalu naik ke700(PREV). Setelah waktu tunggu aplikasi sebelumnya, aplikasi akan berpindah ke rentang yang di-cache, tempat sistem dapat memadatkan dan mengklaim kembali memorinya tanpa memengaruhi worker.
- Dalam proses worker,
Pada Gambar 2, proses UI tetap berada di 200 sebentar saat Activity-nya berhenti,
lalu naik ke 700, sementara worker tetap berada di 200 dengan RSS anonim sekitar 19 MB. Sebagai perbandingan, Gambar 3 menunjukkan rekaman aktivitas berdurasi 35 detik dari
konfigurasi yang ditempatkan bersama, dengan satu proses tetap berada di 50, lalu 200
dengan semua memori UI-nya.
Untuk menjelajahi tampilan ini, buka rekaman aktivitas terpisah dan rekaman aktivitas yang ditempatkan bersama di UI Perfetto.
3. Membuat kueri jejak memori yang meningkat dengan PerfettoSQL
Jalankan kueri PerfettoSQL berikut di tab Query (SQL) untuk mengukur
rata-rata RSS anonim dan file yang disimpan oleh setiap proses aplikasi Anda di setiap
level oom_score_adj:
INCLUDE PERFETTO MODULE android.memory.process;
SELECT
process_name,
score AS oom_score_adj,
ROUND(SUM(dur) / 1e9, 2) AS duration_sec,
ROUND(SUM(anon_rss * dur) / SUM(dur) / 1048576.0, 1) AS avg_anon_mb,
ROUND(SUM(file_rss * dur) / SUM(dur) / 1048576.0, 1) AS avg_file_mb
FROM memory_oom_score_with_rss_and_swap_per_process
WHERE process_name GLOB 'com.example.app*'
GROUP BY process_name, score
ORDER BY process_name, score;
Contoh output untuk trace terpisah pada Gambar 2:
process_name oom_score_adj duration_sec avg_anon_mb avg_file_mb
com.android.memorylab 0 4.11 93.3 110.4
com.android.memorylab 200 1.06 126.8 110.5
com.android.memorylab 700 9.72 115.1 110.5
com.android.memorylab:remote 0 0.01 NULL NULL
com.android.memorylab:remote 200 12.87 18.9 53.7
Contoh output untuk trace yang ditempatkan bersama pada Gambar 3:
process_name oom_score_adj duration_sec avg_anon_mb avg_file_mb
com.android.memorylab 0 4.10 96.0 110.4
com.android.memorylab 50 16.04 117.6 110.5
com.android.memorylab 200 14.68 116.5 110.6
Dalam konfigurasi terpisah, hanya sekitar 19 MB memori anonim yang tetap berada di
oom_score_adj = 200 setelah detik pertama. Dalam konfigurasi yang ditempatkan bersama,
sekitar 117 MB tetap berada di 50, lalu 200 selama layanan latar depan
berjalan.
← Mengembalikan halaman memori ke OS | ↑ Naik