Kebocoran Memori di Aplikasi Mobile — apa itu, penyebab dan metode deteksi

Penulis: IT Sectr Diterbitkan: 2026-03-29 Waktu membaca: 9 mnt

Kebocoran memori (Memory Leak) — situasi ketika aplikasi menyimpan referensi ke objek yang tidak lagi diperlukan, mencegah garbage collector membebaskan occupied memory. Menurut data LeakCanary, bahkan di aplikasi yang ditulis dengan baik terdapat 3–5 kebocoran per 10.000 baris kode. Setiap kebocoran secara bertahap mengurangi memori yang tersedia, menyebabkan perlambatan dan OutOfMemoryError.

Poin Utama

  • Memory Leak — objek tetap di memori meskipun tidak ada referensi aktif dari logika aplikasi
  • Referensi statis ke Activity atau Context — penyebab kebocoran paling umum di Android
  • LeakCanary — alat standar untuk deteksi otomatis kebocoran di Android
  • WeakReference dan Application Context — teknik dasar pencegahan kebocoran
  • Komponen Lifecycle-aware menghilangkan seluruh kelas kebocoran terkait langganan

Apa itu kebocoran memori

Kebocoran memori (Memory Leak) — situasi di mana suatu objek tetap dapat dijangkau melalui rantai referensi kuat (Strong Reference), meskipun secara logis sudah tidak diperlukan oleh aplikasi. Garbage collector (GC) menganggap objek tersebut hidup dan tidak membebaskan memori yang ditempatinya. Akibatnya, memori heap yang tersedia terus berkurang dan frekuensi jeda GC meningkat.

Berbeda dengan bahasa dengan manajemen memori manual (C, C++), di Java/Kotlin kebocoran bukanlah free() yang terlupakan, melainkan referensi yang terlupakan. Selama ada strong reference dari objek akar (GC Root) ke objek yang bocor, GC menganggapnya diperlukan. GC Root tipikal: field statis, thread aktif, stack panggilan, referensi global JNI.

Bahaya kebocoran adalah efek kumulatifnya. Satu kebocoran 100 KB tidak terlihat, tetapi 100 kebocoran semacam itu memakan 10 MB dan aplikasi mulai melambat karena GC yang sering. Massa kritis kebocoran menyebabkan OutOfMemoryError dan crash aplikasi. Gejala kebocoran: peningkatan konsumsi memori yang konstan pada grafik Profiler, jeda GC yang sering dengan STW (Stop The World) dan penurunan kinerja UI.

Jenis kebocoran umum di aplikasi mobile

Lima jenis kebocoran mencakup 95% kasus dalam pengembangan mobile. Masing-masing memiliki penyebab dan pola karakteristik dalam kode.

Referensi statis ke Activity atau Context

Kebocoran paling terkenal di Android — menyimpan referensi statis ke Activity atau Context. Kode tipikal: field statis Activity yang tidak di-nolkan saat onDestroy(). Selama field statis hidup, seluruh Activity dengan pohon View-nya yang bisa memakan 1–10 MB tetap hidup. Ini adalah kebocoran klasik yang LeakCanary temukan pertama kali.

Solusi: jangan pernah menyimpan Activity atau Context di field statis. Gunakan Application Context untuk singleton yang hidup lebih lama dari Activity. Jika perlu referensi ke Activity — gunakan WeakReference<Activity>.

kotlin
object MySingleton {
    private var weakActivity: WeakReference<Activity>? = null

    fun attach(activity: Activity) {
        weakActivity = WeakReference(activity)
    }
}

Kelas dalam dengan referensi implisit

Kelas anonim dan kelas bersarang non-statis secara implisit menyimpan referensi ke kelas yang mengandungnya. Runnable yang dikirim ke Handler dan dieksekusi setelah onDestroy() menahan seluruh Activity. Callback Retrofit yang menutup Activity melakukan hal yang sama. Ini adalah jenis kebocoran paling berbahaya — referensi implisit tidak terlihat dalam kode.

Ekspresi object dan lambda Kotlin juga menangkap referensi ke kelas eksternal. Buat kelas bersarang menjadi statis (atau top-level di Kotlin) dan teruskan referensi eksternal melalui WeakReference. Untuk lambda, gunakan pendekatan Lifecycle-aware dengan viewLifecycleOwner.

Listener dan langganan yang tidak dibatalkan

Berlangganan ke layanan sistem tanpa pembatalan — kebocoran langsung. SensorManager, LocationManager, NotificationListener yang didaftarkan di onResume() tanpa memanggil unregister di onPause() menahan Activity. Serupa: RxJava Disposable yang tidak ditambahkan ke CompositeDisposable dan coroutine yang dijalankan melalui GlobalScope.

Gunakan komponen Lifecycle-aware: observe() dengan LifecycleOwner secara otomatis berhenti berlangganan saat onDestroy(). Untuk RxJava — viewLifecycleOwner.lifecycle.addObserver dengan DisposableObserver. Untuk coroutine — lifecycleScope.launch() terikat pada siklus hidup.

kotlin
// pembatalan langganan otomatis melalui Lifecycle
viewModel.userData.observe(viewLifecycleOwner) { data ->
    updateUI(data)
}

// coroutine dengan lifecycleScope
lifecycleScope.launch {
    viewModel.loadData().collect { render(it) }
}

Bitmap tanpa recycle

Bitmap memakan jumlah memori heap yang signifikan: satu FullHD-bitmap — 1920 × 1080 × 4 byte = 8.3 MB. Jika Bitmap dibuat untuk setiap elemen daftar dan recycle() tidak dipanggil saat disembunyikan, memori cepat habis. Pada versi Android lama (sebelum 3.0), Bitmap disimpan di memori native, tetapi pada versi modern — di heap Dalvik/ART, dan GC hanya dapat membebaskannya jika tidak ada strong reference.

Gunakan Glide atau Coil untuk memuat gambar — pustaka ini mengelola caching dan recycle secara otomatis. Jika bekerja langsung dengan Bitmap, panggil bitmap.recycle() untuk gambar besar yang tidak lagi ditampilkan dan gunakan inSampleSize untuk memuat saluran yang diperkecil.

Referensi Fragment setelah onDestroyView

Fragment memiliki dua siklus hidup: Fragment itu sendiri dan View-nya. Setelah onDestroyView() pohon View dihancurkan, tetapi Fragment itu sendiri dapat tetap di memori jika ada referensi eksternal. Kesalahan tipikal — menyimpan referensi ke Fragment di adapter ViewPager atau di grafik navigasi yang tidak dibersihkan saat dihancurkan.

Jangan pernah menyimpan referensi ke Fragment di field objek berumur panjang. Gunakan childFragmentManager untuk fragment bersarang dan observe() dengan LifecycleOwner untuk mentransfer data di antara mereka. ViewPager2 telah memecahkan masalah ini di tingkat API: FragmentTransactionAdapter mengelola siklus hidup dengan benar.

Cara mendeteksi kebocoran memori

Deteksi kebocoran memerlukan pemeriksaan dua fakta: memori tidak kembali setelah expected lifetime dan jumlah objek dari tipe tertentu meningkat tanpa penurunan. Proses diagnostik mencakup tiga tahap.

Tahap pertama — pemeriksaan visual melalui Memory Profiler di Android Studio. Buka tab Memory, lakukan tindakan target (buka dan tutup layar), tekan GC (Garbage Collection) dan lihat apakah memori kembali ke tingkat awal. Jika setelah 3–4 siklus buka-tutup memori terus meningkat — ada kebocoran.

Tahap kedua — mengambil Heap Dump. Di Memory Profiler tekan Dump Java Heap. File .hprof yang diperoleh buka di Android Studio: Anda akan melihat semua objek di heap dengan ukuran dan referensi. Cari kelas yang jumlahnya harus nol setelah layar ditutup. Misalnya, MainActivity dengan jumlah 2 setelah ditutup — kebocoran yang jelas.

Tahap ketiga — analisis Retained Size dan GC Root. Di Android Studio analisis Retained Size: berapa banyak memori yang akan dibebaskan jika Anda menghapus objek ini. Jalur dari GC Root ke objek menunjukkan apa yang menahannya: Static field → HashMap → Activity — dan Anda melihat titik kebocoran. Panel Reference widget menunjukkan semua pemegang objek.

Alat untuk mencari kebocoran

Empat alat mencakup pencarian kebocoran dari deteksi otomatis hingga analisis Heap Dump mendalam.

AlatMetodeFormat Hasil
LeakCanaryPemantauan otomatisHeap Dump + stack trace kebocoran
Android Memory ProfilerPemantauan manualGrafik memori + Heap Dump
MAT (Eclipse)Analisis mendalamLaporan Dominator Tree + jalur GC Root
PerfettoPelacakan system-wideGaris waktu + memori native

LeakCanary — must-have untuk setiap proyek Android. Secara otomatis mendeteksi kebocoran setelah siklus hidup Activity/Fragment berakhir dan menunjukkan lokasi tepat kebocoran dengan stack trace. Integrasi: satu baris di build.gradle. LeakCanary 2.x tidak memerlukan inisialisasi manual — secara otomatis mendaftarkan Application Watcher.

Cara mencegah kebocoran memori

Pencegahan kebocoran dibangun ke dalam proses pengembangan melalui seperangkat aturan dan alat yang memeriksa kode di setiap tahap.

Aturan referensi kuat

Jangan pernah menyimpan referensi ke Activity, Fragment atau View di field statis, singleton atau objek berumur panjang. Jika referensi tidak dapat dihindari — gunakan WeakReference atau simpan data melalui ViewModel yang hidup persis selama yang diperlukan dan tidak menyimpan View secara langsung.

Arsitektur Lifecycle-aware

ViewModel dan LiveData dari Android Architecture Components memecahkan masalah siklus hidup di tingkat arsitektur. ViewModel bertahan dari rotasi layar dan tidak mengandung referensi ke View. LiveData secara otomatis berhenti berlangganan observer saat onDestroy(). Gunakan mereka daripada berlangganan manual ke layanan sistem.

Code Review dengan fokus pada GC Root

Pada code review perhatikan: field statis dengan tipe Context/View, kelas anonim, lambda yang menutup Activity, langganan manual, RxJava disposable tanpa composite, penyimpanan Fragment melalui Bundle. Di Kotlin, periksa juga coroutine untuk launch tanpa ikatan ke siklus hidup.

Pemeriksaan otomatis di CI

LeakCanary dapat berfungsi sebagai bagian dari pipeline pengujian: jalankan pengujian penerimaan dengan LeakCanary dan tandai build gagal jika ditemukan kebocoran. Ini mencegah kebocoran masuk ke produksi. Lengkapi pemeriksaan dengan Android Lint dengan aturan StaticFieldLeak — aturan ini menemukan potensi kebocoran di tingkat analisis statis.

kotlin
// LeakCanary dalam pengujian
class LeakTest {
    @Test
    fun activityShouldNotLeak() {
        ActivityScenario.launch(MainActivity::class.java)
            .close()
        LeakAssertions.assertNoLeak() // fail jika ada kebocoran
    }
}

Pertanyaan yang Sering Diajukan

Apa perbedaan kebocoran memori dengan OutOfMemoryError?

Kebocoran adalah penyebab, dan OutOfMemoryError adalah akibat. Satu kebocoran tidak menyebabkan OOM, tetapi akumulasi puluhan kebocoran menghabiskan Heap. OOM adalah pengecualian fatal, dan kebocoran adalah pola yang menyebabkan OOM seiring waktu.

Bagaimana menemukan kebocoran tanpa LeakCanary?

Melalui Android Memory Profiler: buka dan tutup layar 5 kali, setelah setiap penutupan panggil GC. Jika memori tidak kembali ke tingkat dasar — ada kebocoran. Ambil Heap Dump dan temukan di daftar kelas Activity yang jumlahnya lebih dari 0 setelah penutupan.

Bisakah Kotlin mencegah kebocoran di tingkat bahasa?

Sebagian. Kotlin memecahkan masalah null-safety, tetapi tidak mengelola strong references. Coroutine dengan lifecycleScope dan viewModelScope mencegah kebocoran dari tugas latar belakang, dan sealed class serta data class mengurangi jumlah kondisi yang menyebabkan kebocoran. Perlindungan utama — pola arsitektur, bukan fungsi bahasa.

Mengapa LeakCanary menemukan kebocoran yang tidak ada?

LeakCanary terkadang memberikan false positive: suatu objek mungkin ditahan sementara oleh sistem (misalnya, InputMethodManager menahan View terakhir). Periksa secara manual: jika Retained Size < 1 KB dan GC Root adalah layanan sistem, kemungkinan itu adalah alarm palsu.

Apakah kebocoran memori hanya terjadi di Android?

Tidak. Kebocoran mungkin terjadi di platform mana pun dengan GC: iOS (Swift/Objective-C), Flutter (Dart), peramban web (JavaScript). Mekanismenya sama — strong reference dari GC Root. Di iOS, ARC mengelola memori secara otomatis, tetapi retain cycle antar objek menciptakan kebocoran yang sama.

Ringkasan

  • Memory Leak — objek yang tidak bisa dibebaskan GC karena strong reference yang terlupakan
  • Referensi statis ke Activity dan Context — penyebab kebocoran paling umum
  • Referensi implisit melalui kelas anonim, lambda, dan langganan RxJava lebih berbahaya daripada yang eksplisit
  • LeakCanary secara otomatis menemukan kebocoran dan menunjukkan stack trace yang tepat
  • Komponen Lifecycle-aware (ViewModel, LiveData, lifecycleScope) menghilangkan satu kelas kebocoran
  • Heap Dump dan analisis Retained Size — metode utama diagnostik manual
  • Pencegahan mencakup code review pada strong reference dan pemeriksaan CI dengan LeakCanary

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga