4. LeakCanary 集成配置:添加依赖、初始化、自定义配置、忽略已知泄漏
LeakCanary 是 Android 内存泄漏自动检测的“第一道防线”。集成配置看似简单,但版本兼容、初始化时机、混淆规则和自定义能力直接决定能否捕获真实泄漏。本章从排查实战角度,按照“现象识别 → 数据采集 → 原因定位 → 修复动作 → 复测 → 预防”的闭环讲解如何正确配置 LeakCanary,并绕过已知的误报泄漏。
4.1 现象识别
未集成 LeakCanary 的 App 在发生泄漏时,只会出现 逐步卡顿、OOM 或 GC 频繁 等间接现象,无法直击泄漏源头。集成后的典型正向现象为:当 Activity/Fragment 销毁后,如果该实例未被回收,LeakCanary 会在 Logcat 输出类似以下日志,并在通知栏弹出提醒:
D/LeakCanary: In com.example.app.xxxActivity@123456789: 1 retained objects
D/LeakCanary: Watching instance of android.widget.TextView (LeakCanary does not watch Android views by default)
...
W/LeakCanary: ====================================
W/LeakCanary: HEAP ANALYSIS RESULT
W/LeakCanary: ====================================
W/LeakCanary: 1 retained object, 1 leak found
W/LeakCanary: * LEAK: Activity xxxActivity leaked
⚠️ 现象识别排查要点:如果集成了 LeakCanary 但从未看到任何泄漏报告,或者报告全是系统/第三方库的泄漏(如 InputMethodManager、MediaSession),应进入下一步排查配置是否覆盖了业务代码。
4.2 数据采集——集成配置清单
集成配置属于“数据采集”阶段:只有正确配置了采集器(LeakCanary),后续的堆转储和分析才有意义。下面按照步骤列出配置项。
| 步骤 | 配置项 | 典型值/说明 | 排查要点 |
|---|---|---|---|
| 1 | 添加依赖 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.13' | 确保仅 debug 生效;检查版本号是否与 AGP 兼容(建议 2.10+) |
| 2 | 初始化时机 | 在 Application.onCreate() 中调用 LeakCanary.config = ... | 必须在 第一个 Activity onCreate 之前 完成 |
| 3 | 自定义配置 | 内存阈值、监控模式、堆转储目录 | 默认阈值 4MB 可能漏报;模式可选 REACHABLE / UNREACHABLE |
| 4 | 忽略已知泄漏 | 使用 RefWatcherBuilder.ignoringKnownLeaks() 或添加 @IgnoreObjectWatcher | 只忽略确实无害的泄漏,否则会掩盖真实问题 |
| 5 | ProGuard / R8 规则 | 添加 -keep class leakcanary.** { *; } | 缺失会导致堆转储分析时类名混淆,无法定位 |
adb shell dumpsys activity processes | grep leakcanary,若输出包含 leakcanary.internal.InternalLeakCanary 说明服务已启动。
4.3 原因定位——集成失败的故障树
配置完成后如果 LeakCanary 不工作或一直报告无关泄漏,按下表定位根因:
| 故障现象 | 可能原因 | 判断规则 | 修复动作 |
|---|---|---|---|
| 从不弹出通知/Locat无日志 | 依赖未用 debugImplementation 或 release 包 | 开启混淆后检查 APK 中是否有 leakcanary 类 | 切换为 debugImplementation 并 clean rebuild |
| 只报告系统泄漏(如 InputMethodManager) | 未配置忽略已知泄漏,或自定义配置中监视了 Android 组件 | 查看 Report 中的 LeakTrace 第一行是否指向 Android 内部 | 用 ignoringKnownLeaks() 排除,或设置 watchActivities(true) |
| 分析结果全为“no leak”但 App 确实 OOM | 阈值过高或监控模式为 REACHABLE | 强制 GC 后查看 retained 对象数是否为 0 | 降低阈值至 2MB,切换为 UNREACHABLE 模式 |
| 堆转储时崩溃 | OOM 手机内存不足,或混淆导致类名错误 | 查看 LeakCanaryInternal.leakDirectoryProvider 是否有写权限 | 增大堆转储超时、添加混淆保留规则 |
4.4 修复动作——一步步纠正配置
以下是针对最常见的场景编写的修复步骤。请按序号执行,每完成一步可回到现象识别阶段验证。
4.4.1 添加依赖(Gradle)
// build.gradle (Module: app)
dependencies {
// 其他依赖…
// LeakCanary 2.x 使用 debugImplementation 确保 Release 包不含
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.13'
// 可选:需要堆转储分析报告时添加 Matcher 支持
// debugImplementation 'com.squareup.leakcanary:leakcanary-object-watcher-android:2.13'
}
检查清单:
- 确认
debugImplementation而非implementation。 - 若在
libs.versions.toml中统一管理,注意 catalog 中是否正确指定了debug配置。 - 同步后执行
./gradlew :app:dependencies --configuration debugRuntimeClasspath确认 leakcanary 出现在依赖树中。
4.4.2 自定义 Application 中初始化
// MyApplication.kt
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// LeakCanary 2.x 无需手动 install,但自定义配置必须在 install 之前
if (LeakCanary.isInAnalyzerProcess(this)) {
// 分析进程只做分析,不执行业务初始化
return
}
val config = LeakCanary.config
.copy(
// 内存泄漏检测阈值(单位:字节),默认 4MB,建议调低以捕捉小泄漏
retainedVisibleThreshold = 2 * 1024 * 1024, // 2MB
// 监控模式:REACHABLE 只报告可达泄漏;UNREACHABLE 报告所有残留对象
leakDetection = LeakDetection.UNREACHABLE,
// 自定义堆转储目录(可选),默认 cache
heapDumpDirectory = File(cacheDir, "leakcanary_dumps")
)
LeakCanary.config = config
// 可选:监视 Fragment 等其他对象
// RefWatcherBuilder.watchFragmentViews(this)
}
}
常见初始化顺序错误:
- 在
onCreate()之后才设置 config → 无效,LeakCanary 在 attachBaseContext 后就已启动默认配置。 - 在分析进程中也做了业务初始化 → 导致分析进程 OOM 或 ANR(应使用
isInAnalyzerProcess跳过)。
4.4.3 忽略已知泄漏
Android 系统本身存在一些无法避免的泄漏(如 InputMethodManager、MediaSession、TextView),这些泄漏不应该由我们的 App 修复。通过 ignoringKnownLeaks() 统一忽略:
// 在 custom Application 中继续配置
val config = LeakCanary.config.copy(
// 使用内置的已知泄漏列表
ignoringKnownLeaks = true,
// 或自定义忽略类
ignoredClassPatterns = listOf("android.inputmethodservice.*", "android.media.*")
)
LeakCanary.config = config
如果需要忽略特定 Activity 的泄漏(例如第三方 SDK 中的 Activity),可在对应类上添加注解:
@IgnoreObjectWatcher
class ThirdPartySdkActivity : Activity() { /* SDK 内部实现 */ }
4.5 复测——验证配置生效
完成修复后,用以下步骤做“一票否决”复测:
- 强制触发一个简单泄漏:在某个 Activity 中创建一个静态变量持有该 Activity 的 Context,然后 finish 该 Activity。等待 5 秒,LeakCanary 应弹出通知。
- 检查 Logcat:过滤
LeakCanary标签,应看到Watching instance of …和1 retained objects。 - 检查 Notification:下拉通知栏,点击 LeakCanary 的“Dump heap & analyze”按钮,应弹出堆转储分析结果。
- 验证忽略规则:恢复上述代码,在
ignoringKnownLeaks = true状态下,重复步骤 1,此时不应再报告该泄漏(如果报出,说明忽略规则未生效)。
com.squareup.leakcanary:leakcanary-android-instrumentation,可在 UI 测试后自动检测泄漏并失败构建。
4.6 预防——持续集成配置
为避免后期大规模集成时出现配置遗漏或版本不一致,应在项目层面建立以下预防措施:
- 依赖版本策略:在
build.gradle.kts中使用libs.versions.toml统一管理 LeakCanary 版本,并通过enforcedUpdate锁定。 - 初始化模板:在团队公共
AppBaseModule中提供预制LeakCanaryConfigProvider类,新业务模块直接继承或注入。 - 已知泄漏清单管理:维护一个
LeakExcludeList.kt文件,每次 Code Review 时必须同步更新该文件并说明排除理由。 - 混淆规则自动测试:在单元测试中执行
RefWatcherBuilder.checkProguardRules()断言混淆正确保留。
| 检查项 | 标准 | 状态 |
|---|---|---|
| 依赖范围 | debugImplementation 且无 release 变体 | ☐ |
| 初始化位置 | Application.onCreate() 中,分析进程分支正确 | ☐ |
| 自定义配置 | 阈值/模式/转储目录按业务调整 | ☐ |
| 忽略规则 | 仅包含评审通过的已知泄漏 | ☐ |
| 混淆规则 | 已添加 leakcanary 保留规则 | ☐ |
| 强制泄漏复测 | 已通过手动/自动化验证 | ☐ |