lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

Menampilkan Heap Java dan Alokasi Memori dengan Memory Profiler

Memory Profiler adalah komponen di Android Profiler yang membantu Anda mengidentifikasi kebocoran memori dan memory churn yang bisa menyebabkan aplikasi tersendat, macet, dan bahkan tidak bekerja. Komponen ini menampilkan grafik realtime dari penggunaan memori oleh aplikasi Anda, memungkinkan Anda merekam heap-dump, memaksa pengumpulan sampah, dan melacak alokasi memori.

Untuk membuka Memory Profiler, ikuti langkah-langkah ini:

  1. Klik View > Tool Windows > Android Profiler (Anda juga bisa mengklik Android Profiler di toolbar).
  2. Pilih perangkat dan proses aplikasi yang ingin Anda buat profilnya dari toolbar Android Profiler. Jika Anda menghubungkan perangkat melalui USB namun tidak melihatnya dicantumkan, pastikan Anda telah mengaktifkan proses debug USB.
  3. Klik di mana saja di timeline MEMORY untuk membuka Memory Profiler.

Atau, Anda bisa memeriksa memori aplikasi dari baris perintah dengan dumpsys, dan juga lihat GC event di logcat.

Mengapa Anda harus membuat profil memori aplikasi

Android menyediakan lingkungan memori terkelola—bila mengetahui bahwa aplikasi Anda tidak lagi menggunakan beberapa objek, pengumpul sampah akan melepas kembali memori ke heap. Cara Android melakukan pencarian memori yang tidak terpakai akan terus ditingkatkan, namun pada beberapa titik di semua versi Android, sistem harus menghentikan kode Anda sesaat. Umumnya, jeda itu tidak akan terasa. Akan tetapi, jika aplikasi Anda mengalokasikan memori lebih cepat daripada yang bisa dikumpulkan oleh sistem, aplikasi Anda mungkin akan tertunda saat pengumpul tersebut membebaskan memori yang cukup untuk memenuhi alokasi Anda. Tundaan tersebut bisa menyebabkan aplikasi Anda melewati beberapa bingkai dan menyebabkan kelambatan yang kentara.

Bahkan jika aplikasi Anda tidak menunjukkan kelambatan, jika membocorkan memori, aplikasi bisa mempertahankan memori itu bahkan saat aplikasi berada di latar belakang. Perilaku ini bisa memperlambat kinerja memori bagian sistem selebihnya dengan memaksa event pengumpulan sampah yang tidak perlu. Pada akhirnya, sistem akan dipaksa untuk mematikan proses aplikasi Anda guna mengambil kembali memori tersebut. Selanjutnya bila pengguna kembali ke aplikasi Anda, aplikasi harus melakukan restart penuh.

Untuk membantu mencegah masalah ini, Anda harus menggunakan Memory Profiler untuk melakukan yang berikut ini:

  • Mencari pola alokasi memori yang tidak diinginkan di timeline yang mungkin menyebabkan masalah kinerja.
  • Menimbun heap Java untuk mengetahui objek mana yang menggunakan memori pada suatu waktu. Sejumlah heap-dump selama jangka waktu tambahan bisa membantu mengidentifikasi kebocoran memori.
  • Merekam alokasi memori selama interaksi pengguna yang normal dan ekstrem untuk mengidentifikasi secara persis di mana kode Anda mengalokasikan terlalu banyak objek dalam waktu singkat atau mengalokasikan objek yang menjadi bocor.

Untuk informasi tentang praktik pemrograman yang bisa mengurangi penggunaan memori aplikasi Anda, bacalah Mengelola Memori Aplikasi Anda.

Ringkasan Memory Profiler

Saat pertama kali membuka Memory Profiler, Anda akan melihat timeline detail atas penggunaan memori aplikasi dan mengakses alat untuk memaksa pengumpulan sampah, merekam heap-dump, dan merekam alokasi memori.

Gambar 1. Memory Profiler

Sebagaimana ditunjukkan dalam gambar 1, tampilan default untuk Memory Profiler menyertakan yang berikut ini:

  1. Tombol untuk memaksa event pengumpulan sampah.
  2. Tombol untuk merekam heap-dump.
  3. Tombol untuk merekam alokasi memori. Tombol ini hanya muncul saat terhubung ke perangkat yang menjalankan Android 7.1 atau yang lebih rendah.
  4. Tombol untuk memperbesar/memperkecil tampilan timeline.
  5. Tombol untuk melompat maju ke data memori langsung.
  6. Event-timeline yang menampilkan keadaan aktivitas, event masukan pengguna, dan event rotasi layar.
  7. Timeline penggunaan memori, yang berisi berikut ini:
    • Grafik bertumpuk tentang banyaknya memori yang sedang digunakan oleh setiap kategori memori, sebagaimana ditunjukkan oleh sumbu-y di sebelah kiri dan kunci warna di bagian atas.
    • Garis putus-putus menunjukkan jumlah objek yang dialokasikan, sebagaimana ditunjukkan oleh sumbu-y di sebelah kanan.
    • Ikon untuk setiap event pengumpulan sampah.

Akan tetapi, jika Anda menggunakan perangkat yang menjalankan Android 7.1 atau yang lebih rendah, tidak semua data pembuatan profil akan terlihat secara default. Jika Anda melihat pesan yang mengatakan, "Advanced profiling is unavailable for the selected process," maka Anda perlu mengaktifkan pembuatan profil lanjutan untuk melihat yang berikut ini:

  • Event-timeline
  • Jumlah objek yang dialokasikan
  • Event pengumpulan sampah

Pada Android 8.0 dan yang lebih tinggi, pembuatan profil lanjutan selalu diaktifkan untuk aplikasi yang bisa di-debug.

Cara menghitung memori

Angka yang Anda lihat di bagian atas Memory Profiler (gambar 2) adalah berdasarkan pada semua halaman memori pribadi yang telah di-commit oleh aplikasi Anda, sesuai dengan sistem Android. Jumlah ini tidak termasuk halaman yang digunakan bersama sistem atau aplikasi lain.

Gambar 2. Keterangan jumlah memori di bagian atas Memory Profiler

Kategori di jumlah memori adalah seperti berikut:

  • Java: Memori dari objek yang dialokasikan dari kode Java atau Kotlin.
  • Bawaan: Memori dari objek yang dialokasikan dari kode C atau C++.

    Sekalipun Anda tidak menggunakan C++ di aplikasi, Anda mungkin akan melihat beberapa memori bawaan yang digunakan di sini karena framework Android menggunakan memori bawaan untuk menangani beragam tugas atas nama Anda, misalnya saat menangani aset gambar dan grafik lainnya—walaupun kode yang Anda tulis dalam bahasa Java atau Kotlin.

  • Graphics: Memori yang digunakan untuk antrean buffering grafik untuk menampilkan piksel ke layar, termasuk permukaan GL, tekstur GL, dan seterusnya. (Perhatikan, ini adalah memori yang digunakan bersama CPU, buka memori yang dikhususkan untuk GPU.)

  • Stack: Memori yang digunakan oleh tumpukan bawaan maupun tumpukan Java di aplikasi Anda. Biasanya ini berkaitan dengan banyaknya thread yang dijalankan oleh aplikasi Anda.

  • Code: Memori yang digunakan aplikasi Anda untuk kode dan sumber daya, misalnya dex bytecode, kode dex yang telah dikompilasi atau dioptimalkan, library .so, dan font.

  • Other: Memori yang digunakan oleh aplikasi Anda yang tidak diketahui sistem cara mengelompokkannya.

  • Allocated: Jumlah objek Java/Kotlin yang dialokasikan oleh aplikasi Anda. Jumlah ini tidak menghitung objek yang dialokasikan di C atau C++.

    Saat terhubung ke perangkat yang menjalankan Android 7.1 dan yang lebih rendah, penghitungan alokasi ini hanya dimulai pada saat Memory Profiler terhubung ke aplikasi yang sedang dijalankan. Sehingga objek yang dialokasikan sebelum Anda memulai pembuatan profil tidak diperhitungkan. Akan tetapi, Android 8.0 menyertakan sebuah alat pembuatan profil pada-perangkat yang melacak semua alokasi, sehingga angka ini selalu menyatakan total jumlah objek Java yang masih harus diselesaikan dalam aplikasi Anda pada Android 8.0 dan yang lebih tinggi.

Bila dibandingkan dengan penghitungan memori dari alat Android Monitor sebelumnya, Memory Profiler yang baru merekam memori Anda secara berbeda, jadi mungkin seakan-akan penggunaan memori Anda sekarang lebih tinggi. Memory Profiler memantau beberapa kategori ekstra yang menambah total, namun jika Anda hanya mempedulikan memori heap Java, maka angka "Java" akan mirip dengan nilai dari alat sebelumnya.

Dan walaupun angka Java mungkin tidak persis sama dengan yang Anda lihat di Android Monitor, angka yang baru ini meliputi semua halaman memori fisik yang telah dialokasikan ke heap Java aplikasi Anda sejak awal pengembangannya. Jadi ini menyediakan representasi akurat mengenai berapa banyak memori fisik yang sesungguhnya digunakan oleh aplikasi Anda.

Catatan: Saat ini, Memory Profiler juga menampilkan beberapa penggunaan memori bawaan palsu di aplikasi Anda yang sesungguhnya dimiliki oleh alat pembuatan profil. Hingga 10 MB memori telah ditambahkan untuk ~100.000 objek. Dalam versi mendatang alat ini, angka ini akan difilter dari data Anda.

Menampilkan alokasi memori

Alokasi memori menampilkan bagaimana setiap objek di memori Anda dialokasikan. Khususnya, Memory Profiler bisa menampilkan yang berikut ini dalam alokasi objek:

  • Tipe objek yang dialokasikan dan banyaknya ruang yang digunakan.
  • Pelacakan tumpukan setiap alokasi, termasuk di thread mana alokasinya.
  • Kapan objek dibebaskan alokasinya (hanya saat menggunakan perangkat yang menjalankan Android 8.0 atau yang lebih tinggi).

Jika perangkat Anda menjalankan Android 8.0 atau yang lebih tinggi, Anda bisa menampilkan alokasi objek kapan saja seperti berikut: Cukup klik-dan-tahan di timeline dan seret untuk memilih region yang ingin Anda tampilkan alokasinya (seperti yang ditampilkan dalam video 1). Tidak perlu memulai sesi perekaman karena Android 8.0 dan yang lebih tinggi menyertakan alat pembuatan profil pada-perangkat yang terus-menerus melacak alokasi aplikasi Anda.

Video 1. Pada Android 8.0 dan yang lebih tinggi, pilih area timeline yang ada untuk menampilkan alokasi objek

Jika perangkat Anda menjalankan Android 7.1 atau yang lebih rendah, klik Record memory allocations di toolbar Memory Profiler. Saat merekam, Android Monitor melacak semua alokasi yang terjadi di aplikasi Anda. Bila Anda selesai, klik Stop recording (tombol yang sama; lihat video 2) untuk menampilkan alokasi.

Video 2. Pada Android 7.1 dan yang lebih rendah, Anda harus secara eksplisit merekam alokasi memori

Setelah Anda memilih region timeline (atau bila Anda menyelesaikan sesi perekaman pada perangkat yang menjalankan Android 7.1 atau yang lebih rendah), daftar objek yang dialokasikan akan muncul di bawah timeline, dikelompokkan menurut nama kelas dan diurutkan sesuai jumlah heap.

Catatan: Pada Android 7.1 dan yang lebih rendah, Anda bisa merekam maksimum 65535 alokasi. Jika sesi perekaman Anda melebihi batas ini, hanya 65535 alokasi terbaru yang akan disimpan dalam catatan. (Tidak ada batas praktis pada Android 8.0 dan yang lebih tinggi.)

Untuk memeriksa catatan alokasi, ikuti langkah-langkah ini:

  1. Jelajahi daftar untuk menemukan objek yang tidak biasanya memiliki jumlah heap besar dan yang mungkin telah bocor. Untuk membantu mengetahui berbagai kelas, klik header kolom Class Name untuk mengurutkan secara abjad. Kemudian klik nama kelas. Panel Instance View muncul di sebelah kanan, yang menampilkan setiap instance kelas itu, seperti yang ditampilkan dalam gambar 3.
  2. Di panel Instance View, klik sebuah instance. Tab Call Stack muncul di bawah, yang menampilkan tempat mengalokasikan instance itu dan di thread yang mana.
  3. Di tab Call Stack, klik pada sembarang garis untuk melompat ke kode itu di editor.

Gambar 3. Detail tentang setiap objek yang dialokasikan muncul dalam Instance View di sebelah kanan

Secara default, daftar alokasi di sebelah kiri disusun menurut nama kelas. Di bagian atas daftar, Anda bisa menggunakan drop-down di sebelah kanan untuk beralih di antara susunan berikut:

  • Arrange by class: Mengelompokkan semua alokasi berdasarkan nama kelas.
  • Arrange by package: Mengelompokkan semua alokasi berdasarkan nama paket.
  • Arrange by callstack: Mengelompokkan semua alokasi ke dalam tumpukan panggilan masing-masing.

Merekam heap-dump

Sebuah heap-dump menampilkan objek mana di aplikasi Anda yang menggunakan memori pada saat Anda merekam heap-dump. Khususnya setelah perpanjangan sesi pengguna, heap-dump bisa membantu mengidentifikasi kebocoran memori dengan menampilkan objek yang masih di memori yang menurut Anda seharusnya tidak ada lagi di sana. Setelah merekam heap-dump, Anda bisa menampilkan yang berikut ini:

  • Tipe objek yang dialokasikan untuk aplikasi Anda dan jumlahnya masing-masing.
  • Banyaknya memori yang digunakan setiap objek.
  • Tempat menyimpan referensi ke setiap objek dalam kode Anda.
  • Tumpukan panggilan untuk tempat mengalokasikan objek. (Tumpukan panggilan saat ini hanya tersedia bersama heap-dump pada Android 7.1 dan yang lebih rendah bila Anda merekam heap-dump saat merekam alokasi.)

Gambar 4. Menampilkan heap-dump

Untuk merekam heap-dump, klik Dump Java heap di toolbar Memory Profiler. Saat menimbun heap, jumlah memori Java mungkin bertambah untuk sementara. Hal ini normal karena heap-dump terjadi dalam proses yang sama dengan aplikasi Anda dan memerlukan banyak memori untuk mengumpulkan data.

Heap-dump akan muncul di bawah timeline memori, yang menampilkan semua tipe kelas di heap, seperti yang ditampilkan dalam gambar 4.

Catatan: Jika perlu lebih akurat tentang kapan timbunan dibuat, Anda bisa membuat heap-dump pada titik kritis di kode aplikasi Anda dengan memanggil dumpHprofData().

Untuk memeriksa heap Anda, ikuti langkah-langkah ini:

  1. Jelajahi daftar untuk menemukan objek yang tidak biasanya memiliki jumlah heap besar dan yang mungkin telah bocor. Untuk membantu mengetahui berbagai kelas, klik header kolom Class Name untuk mengurutkan secara abjad. Kemudian klik nama kelas. Panel Instance View muncul di sebelah kanan, yang menampilkan setiap instance kelas itu, seperti yang ditampilkan dalam gambar 5.
  2. Di panel Instance View, klik sebuah instance. Tab References muncul di bawah, yang menampilkan setiap referensi ke objek itu.

    Atau, klik panah di sebelah nama instance untuk menampilkan semua kolomnya, kemudian klik nama kolom untuk menampilkan semua referensinya. Dan jika Anda ingin menampilkan detail instance untuk sebuah kolom, klik-kanan pada kolom tersebut dan pilih Go to Instance.

  3. Di tab References, jika Anda mengidentifikasi suatu referensi yang mungkin membocorkan memori, klik-kanan pada referensi itu dan pilih Go to Instance. Ini memilih instance yang bersangkutan dari heap-dump, yang menampilkan data instance-nya sendiri.

Secara default, heap-dump tidak menampilkan pelacakan tumpukan untuk setiap objek yang dialokasikan. Untuk mendapatkan pelacakan tumpukan, Anda harus mulai merekam alokasi memori sebelum mengklik Dump Java heap. Selanjutnya, Anda bisa memilih instance di Instance View dan melihat tab Call Stack di sepanjang tab References, seperti yang ditampilkan dalam gambar 5. Akan tetapi, ada kemungkinan beberapa objek telah dialokasikan sebelum Anda mulai merekam alokasi, sehingga tumpukan panggilan tidak tersedia untuk objek-objek itu. Instance yang tidak menyertakan tumpukan panggilan ditunjukkan dengan badge "stack" pada ikon . (Sayangnya, karena pelacakan tumpukan mengharuskan Anda melakukan perekaman alokasi, maka saat ini Anda tidak bisa melihat pelacakan tumpukan untuk heap-dump di Android 8.0.)

Di heap-dump Anda, carilah kebocoran memori yang disebabkan oleh salah satu hal berikut:

  • Referensi berumur-panjang ke Activity, Context, View, Drawable, dan objek lain yang mungkin memiliki referensi ke kontainer Activity atau Context.
  • Kelas dalam non-statis, seperti Runnable, yang bisa menyimpan sebuah instance Activity.
  • Cache yang menyimpan objek lebih lama dari yang diperlukan.

Gambar 5. Durasi yang diperlukan untuk merekam heap-dump ditunjukkan di timeline

Dalam daftar kelas, Anda bisa melihat informasi berikut:

  • Heap Count: Jumlah instance di heap.
  • Shallow Size: Total ukuran semua instance di heap ini (dalam byte).
  • Retained Size: Total ukuran memori yang ditahan akibat semua instance kelas ini (dalam byte).

Di bagian atas daftar kelas, Anda bisa menggunakan menu drop-down untuk beralih di antara heap-dump berikut:

  • Default heap: Bila tidak ada heap yang ditetapkan oleh sistem.
  • App heap: Heap utama tempat aplikasi Anda mengalokasikan memori.
  • Image heap: Citra booting sistem, yang berisi berbagai kelas yang telah termuat selama booting. Alokasi di sini dijamin tidak akan pernah berpindah atau hilang.
  • Zygote heap: Heap salin-saat-menulis yang menjadi tempat pemrosesan aplikasi di sistem Android.

Secara default, daftar objek di heap disusun menurut nama kelas. Anda bisa menggunakan drop-down lainnya untuk beralih di antara susunan berikut:

  • Arrange by class: Mengelompokkan semua alokasi berdasarkan nama kelas.
  • Arrange by package: Mengelompokkan semua alokasi berdasarkan nama paket.
  • Arrange by callstack: Mengelompokkan semua alokasi ke dalam tumpukan panggilan masing-masing. Opsi ini hanya cocok jika Anda merekam heap-dump sambil merekam alokasi. Walau demikian, mungkin saja ada objek di heap yang dialokasikan sebelum Anda memulai perekaman, jadi alokasi itu akan muncul terlebih dahulu, yang hanya dicantumkan menurut nama kelas.

Secara default, daftar diurutkan menurut kolom Retained Size. Anda bisa mengklik header kolom mana saja untuk mengubah cara mengurutkan daftar.

Di Instance View, setiap instance menyertakan yang berikut ini:

  • Depth: Jumlah lompatan tersingkat dari GC root ke instance yang dipilih.
  • Shallow Size: Ukuran instance ini.
  • Retained Size: Ukuran memori yang didominasi oleh instance (berdasarkan pohon dominator).

Menyimpan heap-dump sebagai HPROF

Setelah Anda merekam heap-dump, data akan terlihat di Memory Profiler saja saat profiler dijalankan. Bila keluar dari sesi pembuatan profil, Anda akan kehilangan heap-dump tersebut. Jadi jika Anda ingin menyimpannya untuk ditinjau nanti, eksporlah heap-dump ke file HPROF dengan mengklik Export heap dump as HPROF file , di toolbar di bawah timeline. Dalam dialog yang muncul, pastikan menyimpan file dengan akhiran .hprof.

Nanti Anda akan bisa membuka kembali file tersebut di Android Studio dengan menyeret file ke dalam jendela editor kosong, (atau meletakkannya di bilah tab file).

Untuk menggunakan penganalisis HPROF berbeda seperti jhat, Anda perlu mengonversi file HPROF dari format Android ke format HPROF Java SE. Anda bisa melakukannya dengan alat hprof-conv yang disediakan dalam direktori android_sdk/platform-tools/. Jalankan perintah hprof-conv bersama dua argumen: file HPROF asal dan lokasi untuk menuliskan file HPROF yang telah dikonversi. Misalnya:

hprof-conv heap-original.hprof heap-converted.hprof

Teknik untuk pembuatan profil memori Anda

Saat menggunakan Memory Profiler, Anda harus menekankan pada kode aplikasi dan coba memaksa kebocoran memori. Satu cara untuk menyebabkan kebocoran memori di aplikasi adalah dengan membiarkannya berjalan untuk sementara waktu sebelum memeriksa heap. Kebocoran mungkin menetes ke bagian atas alokasi dalam heap tersebut. Akan tetapi, semakin kecil kebocoran, semakin lama Anda perlu menjalankan aplikasi untuk melihatnya.

Anda juga bisa memicu kebocoran memori dengan salah satu cara berikut:

  • Putar perangkat beberapa kali dari potret ke lanskap dan kembali lagi saat dalam keadaan aktivitas yang berbeda. Memutar perangkat sering kali bisa menyebabkan aplikasi membocorkan objek Activity, Context, atau View karena sistem membuat kembali Activity dan jika aplikasi Anda memiliki referensi ke salah satu objek tersebut di tempat lain, sistem tidak dapat melakukan pengumpulan sampah di situ.
  • Beralihlah antara aplikasi Anda dan aplikasi lain saat dalam keadaan aktivitas berbeda (buka layar Utama, kemudian kembali ke aplikasi).

Tips: Anda juga bisa melakukan langkah-langkah di atas dengan menggunakan framework pengujian monkeyrunner.