Alokasi memori di antara proses

Platform Android berjalan pada premis bahwa memori bebas adalah memori yang sia-sia. Android mencoba menggunakan semua memori yang tersedia sepanjang waktu. Misalnya, sistem menyimpan aplikasi yang ditutup di memori sehingga pengguna dapat membukanya kembali dengan cepat. Karena alasan ini, perangkat Android sering berjalan dengan memori bebas yang sangat sedikit. Pengelolaan memori sangat penting untuk mengalokasikan memori dengan baik di antara proses sistem yang penting dan berbagai aplikasi pengguna.

Artikel ini membahas dasar-dasar tentang bagaimana Android mengalokasikan memori untuk sistem dan aplikasi pengguna. Dijelaskan juga bagaimana sistem operasi bereaksi terhadap situasi memori rendah.

Jenis-jenis memori

Perangkat Android memuat tiga jenis memori berbeda: RAM, zRAM, dan penyimpanan. Ingat bahwa CPU dan GPU mengakses RAM yang sama.

Jenis-jenis memori

Gambar 1. Jenis-jenis memori - RAM, zRAM, dan penyimpanan

  • RAM adalah jenis memori tercepat, tetapi biasanya memiliki ukuran terbatas. Perangkat kelas atas biasanya memiliki RAM yang besar.

  • zRAM adalah partisi RAM yang digunakan untuk ruang pertukaran. Apa saja yang ditempatkan dalam zRAM akan dikompresi, lalu didekompresi saat disalin dari zRAM. Ukuran RAM ini bertambah atau berkurang saat halaman dipindahkan ke atau dikeluarkan dari zRAM. Ukuran maksimum ZRAM dapat ditetapkan oleh produsen perangkat.

  • Penyimpanan memuat semua data persisten seperti sistem file dan kode objek yang disertakan untuk semua aplikasi, library, dan platform. Penyimpanan memiliki kapasitas yang jauh lebih besar dibandingkan dua jenis memori lainnya. Di Android, penyimpanan tidak digunakan untuk ruang pertukaran seperti pada implementasi Linux lainnya, karena operasi tulis yang sering dapat menyebabkan keausan pada memori ini dan mempersingkat masa pakai media penyimpanan.

Halaman memori

RAM dipecah menjadi sejumlah halaman. Biasanya, setiap halaman berukuran 4 KB memori.

Halaman dianggap bebas atau terpakai. Halaman bebas adalah RAM yang tidak digunakan. Halaman terpakai adalah RAM yang digunakan sistem secara aktif, dan dikelompokkan ke dalam kategori berikut:

  • Cache: Memori yang didukung oleh sebuah file di penyimpanan (misalnya, file kode atau file yang dipetakan memori). Ada dua jenis memori cache:
    • Pribadi: Dimiliki oleh satu proses dan tidak digunakan bersama
      • Bersih: Salinan tanpa modifikasi dari file yang ada di penyimpanan, dapat dihapus oleh kswapd untuk meningkatkan ukuran memori bebas
      • Kotor: Salinan termodifikasi dari file yang ada di penyimpanan; dapat dipindahkan ke, atau dikompresi dalam, zRAM oleh kswapd untuk meningkatkan ukuran memori bebas
    • Bersama: Digunakan oleh beberapa proses
      • Bersih: Salinan tanpa modifikasi dari file tersebut di penyimpanan, dapat dihapus oleh kswapd untuk meningkatkan ukuran memori bebas
      • Kotor: Salinan termodifikasi dari file tersebut di penyimpanan; memungkinkan perubahan ditulis kembali ke file di penyimpanan untuk meningkatkan ukuran memori bebas oleh kswapd, atau secara eksplisit menggunakan msync() atau munmap()
  • Anonim: Memori yang tidak didukung oleh file di penyimpanan (misalnya, dialokasikan oleh mmap() dengan tanda MAP_ANONYMOUS ditetapkan)
    • Kotor: Dapat dipindahkan/dikompresi dalam zRAM oleh kswapd untuk meningkatkan ukuran memori bebas

Proporsi halaman bebas dan terpakai berubah dari waktu ke waktu karena sistem mengelola RAM secara aktif. Konsep yang diperkenalkan di bagian ini merupakan kunci untuk mengelola situasi memori rendah. Bagian berikutnya dari artikel ini menjelaskannya secara lebih mendetail.

Pengelolaan memori rendah

Android memiliki dua mekanisme utama untuk menangani situasi memori rendah: kernel swap daemon dan low memory killer.

kernel swap daemon

Kernel swap daemon (kswapd) adalah bagian dari kernel Linux, dan mengonversi memori terpakai menjadi memori bebas. Daemon menjadi aktif saat memori bebas di perangkat hampir habis. Kernel Linux menetapkan batas atas dan batas bawah untuk memori bebas. Saat memori bebas turun melebihi batas bawah, kswapd mulai mengklaim kembali memori. Setelah memori bebas mencapai batas atas, kswapd akan menghentikan klaim kembali memori.

kswapd dapat mengklaim ulang halaman bersih dengan cara menghapusnya, karena halaman bersih didukung oleh penyimpanan dan belum dimodifikasi. Jika sebuah proses mencoba mengakses halaman bersih yang telah dihapus, sistem akan menyalin halaman tersebut dari penyimpanan ke RAM. Operasi ini disebut demand paging.

Halaman bersih yang didukung oleh penyimpanan dihapus

Gambar 2. Halaman bersih yang didukung oleh penyimpanan dihapus

kswapd dapat memindahkan halaman kotor pribadi cache dan halaman kotor anonim ke zRAM. Di sini, halaman tersebut akan dikompresi. Cara ini mengosongkan memori yang tersedia di RAM (halaman bebas). Jika sebuah proses mencoba mengakses halaman kotor di zRAM, halaman tersebut akan diekstrak dan dipindahkan kembali ke RAM. Jika proses yang terkait dengan halaman terkompresi dihentikan, maka halaman tersebut akan dihapus dari zRAM.

Jika jumlah memori bebas turun melebihi ambang tertentu, sistem akan memulai proses penghentian.

Halaman kotor dipindahkan ke zRAM dan dikompresi

Gambar 3. Halaman kotor dipindahkan ke zRAM dan dikompresi

Low-memory killer

Sering kali, kswapd tidak dapat mengosongkan cukup memori untuk sistem. Dalam kasus ini, sistem menggunakan onTrimMemory() untuk memberi tahu aplikasi bahwa memori hampir habis dan alokasinya harus dikurangi. Jika cara ini tidak cukup, kernel akan memulai proses penghentian (killing) untuk mengosongkan memori. Low-memory killer (LMK) digunakan untuk keperluan ini.

Untuk menentukan proses yang akan dihentikan, LMK menggunakan skor "out of memory" yang disebut oom_adj_score untuk memprioritaskan proses yang berjalan. Proses dengan skor tinggi akan dihentikan terlebih dahulu. Aplikasi latar belakang dihentikan terlebih dahulu, dan proses sistem dihentikan paling akhir. Tabel berikut mencantumkan kategori skor LMK dari tinggi ke rendah. Item dalam kategori skor tertinggi, di baris pertama, akan dihentikan terlebih dahulu:

Proses Android, skor tertinggi di bagian paling atas

Gambar 4. Proses Android, dengan skor tertinggi di bagian atas dan skor rendah di bagian bawah

Berikut adalah deskripsi untuk berbagai kategori dalam tabel di atas:

  • Aplikasi latar belakang: Aplikasi yang dijalankan sebelumnya dan saat ini tidak aktif. LMK akan terlebih dahulu menghentikan aplikasi latar belakang, dimulai dari aplikasi dengan oom_adj_score tertinggi.

  • Aplikasi sebelumnya: Aplikasi sebelumnya memiliki prioritas lebih tinggi (skor lebih rendah) dibandingkan aplikasi latar belakang karena pengguna lebih mungkin untuk beralih ke aplikasi tersebut daripada ke salah satu aplikasi latar belakang.

  • Aplikasi layar utama: Ini adalah aplikasi peluncur. Menghentikan aplikasi ini akan membuat wallpaper menghilang.

  • Layanan: Layanan dimulai oleh aplikasi dan dapat mencakup sinkronisasi atau upload ke cloud.

  • Aplikasi yang terasa: Aplikasi yang tidak berjalan di latar depan, yang terasa oleh pengguna dengan cara tertentu, seperti menjalankan proses penelusuran yang menampilkan UI kecil atau mendengarkan musik.

  • Aplikasi latar depan: Aplikasi yang sedang digunakan. Menghentikan aplikasi latar depan akan tampak seolah-olah aplikasi mengalami error, yang mungkin menunjukkan kepada pengguna bahwa ada sesuatu yang tidak beres dengan perangkat.

  • Persisten (layanan): Ini adalah layanan inti untuk perangkat, seperti telepon dan Wi-Fi.

  • Sistem: Proses sistem. Saat proses ini dihentikan, ponsel mungkin tampak seperti di-reboot.

  • Native: Proses tingkat sangat rendah yang digunakan sistem (misalnya, kswapd).

Produsen perangkat dapat mengubah perilaku LMK.

Menghitung jejak memori

Kernel melacak semua halaman memori dalam sistem.

Halaman yang digunakan oleh berbagai proses

Gambar 5. Halaman yang digunakan oleh berbagai proses

Saat menentukan banyaknya memori yang digunakan oleh aplikasi, sistem harus memperhitungkan halaman yang digunakan bersama. Aplikasi yang mengakses layanan atau library yang sama akan berbagi halaman memori. Misalnya, Layanan Google Play dan aplikasi game dapat berbagi layanan lokasi. Hal ini menyulitkan untuk menentukan banyaknya memori yang digunakan oleh layanan secara keseluruhan dengan yang digunakan oleh setiap aplikasi.

Halaman yang digunakan bersama oleh dua aplikasi

Gambar 6. Halaman yang digunakan bersama oleh dua aplikasi (tengah)

Untuk menentukan jejak memori sebuah aplikasi, salah satu metrik berikut dapat digunakan:

  • Resident Set Size (RSS): Jumlah halaman bersama dan bukan-bersama yang digunakan oleh aplikasi
  • Propotional Set Size (PSS): Jumlah halaman bukan-bersama yang digunakan oleh aplikasi dan distribusi merata dari halaman bersama (misalnya, jika tiga proses berbagi 3 MB, setiap proses mendapat 1 MB dalam PSS)
  • Unique Set Size (USS): Jumlah halaman bukan-bersama yang digunakan oleh aplikasi (tidak termasuk halaman bersama)

Bagi sistem operasi, PSS berguna untuk mengetahui banyaknya memori yang digunakan oleh semua proses karena halaman tidak dihitung beberapa kali. Penghitungan PSS memerlukan waktu lama karena sistem perlu menentukan halaman mana yang digunakan bersama dan oleh berapa banyak proses. RSS tidak membedakan halaman bersama dengan bukan-bersama (sehingga mempercepat penghitungan) dan lebih baik untuk melacak perubahan dalam alokasi memori.

Referensi lainnya