跳到主要内容

内存泄漏检测

问题

Android 中常见的内存泄漏场景有哪些?如何检测?

答案

常见泄漏场景

场景原因解决方案
Activity 被静态引用静态变量持有 Activity使用 WeakReference 或 Application Context
Handler 泄漏非静态内部类持有外部 Activity 引用使用静态内部类 + WeakReference
匿名内部类/Lambda持有外部类引用注意 Listener 的生命周期
单例持有 Activity单例中缓存了 Activity Context使用 Application Context
未取消的协程协程作用域未随生命周期取消使用 lifecycleScope / viewModelScope
未注销的监听器BroadcastReceiver/Callback 未注销onDestroy 中取消
WebView 泄漏WebView 持有 Activity 引用动态添加/独立进程

经典 Handler 泄漏

// ❌ 内存泄漏:非静态内部类持有 Activity 引用
class MyActivity : AppCompatActivity() {
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
updateUI() // 隐式引用 Activity
}
}
}

// ✅ 修复:静态内部类 + WeakReference
class MyActivity : AppCompatActivity() {
private class SafeHandler(activity: MyActivity) : Handler(Looper.getMainLooper()) {
private val activityRef = WeakReference(activity)
override fun handleMessage(msg: Message) {
activityRef.get()?.updateUI()
}
}

// ✅✅ 更好的方案:直接用协程
private fun delayedUpdate() {
lifecycleScope.launch {
delay(5000)
updateUI() // lifecycleScope 在 onDestroy 自动取消
}
}
}

LeakCanary

build.gradle.kts
dependencies {
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.14")
}

零配置,自动检测 Activity、Fragment、ViewModel、Service 和 View 的泄漏。泄漏时通知栏弹出提示,展示引用链。

LeakCanary 原理


常见面试问题

Q1: LeakCanary 是如何检测 Activity 泄漏的?

答案

  1. 注册 ActivityLifecycleCallbacks 监听 onActivityDestroyed
  2. 将 Activity 包装为 WeakReference,关联 ReferenceQueue
  3. 等待 5 秒后检查 ReferenceQueue,如果 WeakReference 未入队,说明 Activity 未被 GC 回收
  4. 触发手动 GC 再次检查
  5. 仍未回收则抓取 Heap Dump,使用 Shark 库解析引用链

Q2: 如何修复 WebView 内存泄漏?

答案

// 方案 1:动态创建 WebView,使用 Application Context
val webView = WebView(applicationContext)
container.addView(webView)

override fun onDestroy() {
container.removeView(webView)
webView.stopLoading()
webView.destroy()
super.onDestroy()
}

// 方案 2:在独立进程中运行 WebView(彻底隔离)
// AndroidManifest.xml
// <activity android:name=".WebViewActivity" android:process=":webview" />

Q3: Kotlin 协程会导致内存泄漏吗?

答案

如果使用 GlobalScope 或自定义 CoroutineScope 且未正确取消,会导致泄漏。推荐:

  • Activity/Fragment 中用 lifecycleScope
  • ViewModel 中用 viewModelScope
  • 它们都会在组件销毁时自动取消

相关链接