Memory Leak Detection & Prevention

📖 Concept

Memory leaks occur when objects that are no longer needed are still referenced, preventing garbage collection. In Android, Activity and Fragment leaks are the most common and dangerous.

How to detect leaks:

  1. LeakCanary — Automatic detection in debug builds. Watches Activities, Fragments, Views, ViewModels. Shows reference chain.
  2. Android Studio Memory Profiler — Live heap inspection, allocation tracking, heap dump analysis.
  3. adb shell dumpsys meminfo — Quick memory overview per process.

Most common leak patterns in Android:

  1. Static reference to Activity/Context — Singleton holding Activity context
  2. Inner class reference — Non-static inner class holds implicit reference to outer class
  3. Thread/Handler leaks — Long-running operations holding Activity reference
  4. Unregistered callbacks — Listeners, receivers, observers not removed on destroy
  5. View binding not cleared — Fragment's view binding kept after onDestroyView

Leak investigation workflow:

1. Run app with LeakCanary enabled
2. Exercise the suspected flow (navigate in/out of screens)
3. LeakCanary shows toast if leak detected
4. Examine the reference chain (GC root → leak)
5. Identify the retaining reference
6. Fix and verify

Prevention checklist:

  • Use applicationContext instead of Activity context for singletons
  • Clear listeners/callbacks in onStop/onDestroy
  • Null out view binding in Fragment.onDestroyView
  • Use WeakReference for optional callbacks
  • Use lifecycle-aware components (LiveData, Flow with repeatOnLifecycle)

💻 Code Example

codeTap to expand ⛶
1// Common leak patterns and their fixes
2
3// LEAK: ViewModel holding View reference
4class BadViewModel : ViewModel() {
5 var textView: TextView? = null // ❌ ViewModel outlives Activity!
6}
7// FIX: ViewModel exposes StateFlow, View observes it
8class GoodViewModel : ViewModel() {
9 private val _text = MutableStateFlow("")
10 val text: StateFlow<String> = _text.asStateFlow()
11}
12
13// LEAK: Coroutine in Activity without proper scope
14class LeakyActivity : AppCompatActivity() {
15 override fun onCreate(savedInstanceState: Bundle?) {
16 super.onCreate(savedInstanceState)
17 CoroutineScope(Dispatchers.IO).launch { // ❌ Unmanaged scope!
18 delay(60_000)
19 updateUI() // Activity may be destroyed
20 }
21 }
22}
23// FIX: Use lifecycleScope
24class SafeActivity : AppCompatActivity() {
25 override fun onCreate(savedInstanceState: Bundle?) {
26 super.onCreate(savedInstanceState)
27 lifecycleScope.launch { // ✅ Auto-cancelled on destroy
28 delay(60_000)
29 updateUI()
30 }
31 }
32}
33
34// LEAK: Singleton holding Activity context
35object ImageCache {
36 private lateinit var context: Context
37 fun init(context: Context) {
38 this.context = context // ❌ If Activity context, leaked!
39 }
40}
41// FIX: Use application context
42object ImageCache {
43 private lateinit var context: Context
44 fun init(context: Context) {
45 this.context = context.applicationContext // ✅ Application lives forever
46 }
47}
48
49// LeakCanary custom watchers
50class MyApplication : Application() {
51 override fun onCreate() {
52 super.onCreate()
53 // Watch custom objects for leaks
54 val watcher = AppWatcher.objectWatcher
55 // When you expect an object to be GC'd, watch it:
56 // watcher.expectWeaklyReachable(myObject, "reason")
57 }
58}

🏋️ Practice Exercise

Practice:

  1. Set up LeakCanary and intentionally create 3 different types of leaks
  2. Use Memory Profiler to capture a heap dump and identify retained objects
  3. Fix a memory leak caused by a Handler posting delayed messages
  4. Implement a lifecycle-aware callback registration pattern
  5. Profile your app's memory usage across 10 screen transitions — check for growth

⚠️ Common Mistakes

  • Only testing on high-end devices — leaks cause OOM crashes on low-memory devices first

  • Using Activity context in singletons — always use applicationContext for long-lived objects

  • Not testing with LeakCanary in CI — add a leak detection step to your test pipeline

  • Assuming Kotlin's lifecycle features prevent all leaks — coroutine scope leaks are still common

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Memory Leak Detection & Prevention. Login to unlock this feature.