LeakCanary配置与告警链路
当App出现不可关闭的Activity残影或反复GC后内存不降时,我们需要一个自动化的泄漏检测工具来锁定问题对象。LeakCanary正是Android生态中最成熟的泄漏数据采集器:它通过弱引用+GC触发机制判定对象是否泄漏,并在发现泄漏后生成通知与详细引用链。
本章配置的目标是在build.gradle中完成集成,让LeakCanary在开发者构建中自动运行,及时捕获Activity泄漏的第一手证据。
4.1 在build.gradle中集成LeakCanary
- 添加依赖:在
app/build.gradle的dependencies块中加入LeakCanary库。 - Application初始化:若使用定制
Application类,需在onCreate()中调用初始化方法;也可利用ContentProvider自动初始化(推荐)。 - 混淆配置:保留LeakCanary内部类,避免混淆导致检测失效。
- 调试模式限定:LeakCanary仅应在
debug构建类型中启用,防止影响正式包性能。
💡 版本建议:LeakCanary 2.x已默认采用ContentProvider自动初始化,无需手动调用
LeakCanary.install(this)。若你的项目使用多模块,请确保主模块依赖了leakcanary-android。
以下为典型集成配置(Kotlin DSL + AGP 7.x):
// app/build.gradle.kts
dependencies {
// LeakCanary 2.14 (最新稳定版)
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.14")
// 可选:将LeakCanary图标加入通知通道
debugImplementation("com.squareup.leakcanary:leakcanary-object-watcher-android:2.14")
}
// 混淆规则(proguard-rules.pro)
-keep class leakcanary.** { *; }
-keep class com.squareup.leakcanary.** { *; }
4.2 LeakCanary告警链路解析
LeakCanary的告警链路是一条自动化的证据链,它从对象被观测开始,到通知弹出结束。理解这条链路有助于我们在收到告警时快速定位哪个环节出现了缓存引用。
⚠️ 常见误解:LeakCanary不是实时检测,而是在对象被WeakReference包装后,等待下次GC完成时判定。因此从Activity销毁到通知出现可能有数秒延迟,属于正常行为。
| 节点 | 职责 | 常见异常表现 |
|---|---|---|
| ObjectWatcher | 对弱引用进行注册与检测 | 弱引用未被清除 → 判定为潜在泄漏 |
| GcTrigger | 手动触发GC并等待弱引用被入队 | 长时间未GC → 一直无法判定 |
| HeapDumper | 转储堆快照到文件 | 磁盘空间不足 → 转储失败 |
| HeapAnalyzer | 解析hprof查找泄漏引用链 | hprof过大或OOM → 分析失败 |
| NotificationSender | 拼接摘要信息并弹出通知 | 通知通道未配置 → 静默丢失 |
📌 链路关键决策点:在“仍存活?”菱形节点处,LeakCanary通过双重GC+弱引用队列判定对象是否被回收。若对象在GC后仍未被入队,则判定为真正泄漏,进入堆转储阶段。这一机制有效过滤了临时存活的对象(如后台任务刚结束),提高了告警的准确性。
4.3 告警通知的读取与响应
当LeakCanary判定存在Activity泄漏时,会弹出系统通知(通道名“LeakCanary”)。点击通知可打开LeakCanary内部页面,查看泄漏对象摘要和完整引用链(gcRoots → 引用路径)。
- 通知摘要:显示泄漏数量、泄漏的最旧Activity、hprof文件大小。
- 引用链示例:
静态变量 → 缓存容器 → 某个Fragment → Activity,这正是我们后续定位缓存引用的关键线索。