第1章 LeakCanary原理与工作流程:引用链分析、弱引用机制、Android生命周期钩子
1.1 核心原理
LeakCanary 是一款自动检测 Android 应用内存泄漏的工具。其核心原理基于三个关键技术:
- 弱引用(WeakReference)+ 引用队列(ReferenceQueue):当一个对象只持有弱引用时,GC 可以在下一次回收时将其回收,并将该弱引用放入关联的引用队列。若对象应该被回收但弱引用未进入队列,说明对象仍被强引用持有,即发生泄漏。
- Android 生命周期钩子:通过注册
ActivityLifecycleCallbacks和FragmentLifecycleCallbacks,在 Activity/Fragment 执行onDestroy()后立即注入监视对象。 - 引用链分析:当检测到疑似泄漏时,LeakCanary 触发 Heap Dump,并使用 Shark(自主开发的分析引擎)解析 hprof 文件,从泄漏对象回溯到 GC Root 的最短引用路径,以可视化方式展示给开发者。
1.2 工作流程
一次完整的检测周期包含以下步骤:
- 注册监听:在
Application.onCreate()中初始化 LeakCanary,并注册生命周期回调。 - 对象入队:当 Activity/Fragment 销毁时,LeakCanary 创建一个强引用
keyedWeakReference包裹该对象,并关联一个随机 UUID key,将 key 存入refWatcher的待检测集合。 - 延时等待 GC:延迟 5 秒(默认)后主动请求一次 GC,然后检查弱引用是否已被回收(即引用队列中是否出现该 weakReference)。
- 判定泄漏:若弱引用仍未入队,则认为对象泄漏,触发 Heap Dump。
- 分析并展示:解析 Dump 文件,构建引用链,将结果以通知或 Log 形式输出。
关键参数:可通过
LeakCanary.config 修改等待 GC 时长、是否保留 Heap Dump 文件等。
1.3 工作流程内联 SVG
1.4 代码接入与配置
在 build.gradle 中添加依赖(以 LeakCanary 2.x 为例):
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.12'
}
Application 中无需额外初始化,LeakCanary 会自动通过 ContentProvider 注册。如需自定义配置,可在 Application 中调用:
LeakCanary.config = LeakCanary.config.copy(
// 保留最近 3 次 dump
retainedVisibleCount = 3,
// 自定义 GC 等待时间(毫秒)
watchDurationMillis = 7000L,
// 是否分析不可达对象
computeRetainedHeapSize = true
)
1.5 生命周期钩子注册细节
| 钩子类型 | 注册方式 | 监听回调 |
|---|---|---|
| Activity 生命周期 | Application.registerActivityLifecycleCallbacks |
onActivityDestroyed |
| Fragment 生命周期 | FragmentManager.registerFragmentLifecycleCallbacks |
onFragmentDestroyed |
| ViewModel 支持 | 通过 leakcanary-android-process 自动绑定 |
onCleared |
1.6 常见错误与调试
- 泄漏误报:如果 Activity 被保留在非静态内部类中,LeakCanary 会报告泄漏。请检查引用链确认是否属于预期保留(如单例持有 Context)。
- 未初始化:LeakCanary 2.x 自动初始化,若无法检测到泄漏,检查是否正确添加
debugImplementation而非implementation。 - 混淆规则:如果启用了混淆,需添加以下 ProGuard 规则保留引用分析所需类:
-keep class leakcanary.** { *; }
-keep class shark.** { *; }
1.7 性能与稳定性优化
LeakCanary 默认只在 debug 构建中生效,release 构建使用 no-op 空实现。在调试时,Heap Dump 会消耗一定内存和 CPU,建议:
- 在多进程应用中只保留主进程的 LeakCanary 实例(通过
LeakCanary.config的processName过滤)。 - 控制保留的 dump 文件数量(
retainedVisibleCount)以避免磁盘暴涨。 - 在低端设备上可增大
watchDurationMillis以减少 GC 触发频率。
注意:不要在生产环境中开启 LeakCanary 的 Heap Dump 功能,因为 dump 和解析过程可能导致 ANR。始终使用
releaseCompile 的 no-op 版本。