第2章 泄漏证据采集:使用 Android Studio Profiler、Memory Analyzer (MAT)、LeakCanary 抓取堆转储

泄漏证据是定位问题的基石。只有获得内存快照(Heap Dump,即堆转储),才能追溯存活对象的引用链。本章聚焦三种主流抓取工具的操作方法、适用场景和产出差异,帮助你快速锁定可疑对象。

2.1 为什么必须采集堆转储

内存泄漏在小型 Demo 中常通过日志或肉眼观察复现,但在复杂应用中需要精确的 对象引用关系图。堆转储就是这一刻进程内所有 Java / Kotlin 对象的快照:它能揭示哪些 Activity、Fragment、Observer 仍被 GC Root 强引用,从而确认泄漏。

判断规则:如果你怀疑某个 LifecycleOwner(如 Activity)在 onDestroy() 后未被回收,且堆转储中该对象实例数 > 0,则说明存在泄漏。实例数 > 1 意味着重复泄漏(每次重建都残留一个)。

2.2 三种工具的工作原理对比

工具 采集方式 产物格式 是否自动触发 主要用途
Android Studio Profiler 手动点击「Dump Java heap」 .hprof(Android 格式) 否,需要开发者操作 实时观察、对比内存趋势
LeakCanary 自动监测对象回收失败后抓取 .hprof → 内部分析 → 通知 是(自动检测泄漏) 开发自测、QA 测试、线上自动化
Memory Analyzer (MAT) 接收 .hprof 文件离线分析 转换后 *.hprof(标准格式) 否,需手动导入 深度引用链分析、Dominator Tree 查看

2.3 使用 Android Studio Profiler 抓取堆转储

  1. 运行应用并导航到泄漏场景(例如:打开 Activity → 按返回键)。
  2. 打开 View → Tool Windows → Profiler,选择目标进程。
  3. 点击 Memory 图表,稍等数秒使 GC 完成。
  4. 点击工具栏上的 Dump Java heap 按钮(垃圾桶图标左侧)。
  5. 等待 Profiler 生成 .hprof 并自动显示对象列表。

关键技巧:在 Dump 之前先手动触发一次 System.gc() 或点击 Force garbage collection,排除弱引用、软引用干扰,只保留下真正强引用的对象。

2.4 使用 LeakCanary 自动抓取并通知

LeakCanary 是 Square 开源的自动泄漏检测库。适合集成到 debug 构建变体中,无需手动 Dump。

// app/build.gradle (模块级)
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'

// Application.kt
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        // LeakCanary 默认自动初始化;如需自定义,使用 LeakCanary.config
    }
}

集成后每次 Activity 或 Fragment 销毁后,LeakCanary 会自动等待 GC 并检查对象是否被回收。若发现泄漏,会在通知栏弹出提示,点击后可直接查看泄漏痕迹(LeakTrace)并导出 .hprof 文件。

注意:LeakCanary 的自动 Dump 可能影响执行性能,线上版本请勿开启。
若在 release 构建中意外引入 LeakCanary,会导致堆转储频繁触发 → 应用卡顿。

2.5 使用 Memory Analyzer (MAT) 分析标准 HPROF

Android Studio Profiler 导出的 .hprof 文件需经转换才能在 MAT 中使用。

# 使用 Android SDK 提供的工具
$ANDROID_HOME/platform-tools/hprof-conv input.hprof output.hprof

# 或用 Android Studio 自动转换(Profiler 中 Export to standard .hprof)

转换后在 MAT 中打开,使用 Histogram 查看类实例数,使用 Dominator Tree 找到最大的存活对象,右键 Merge Shortest Paths to GC Roots → exclude weak/soft references 查看强引用链。

2.6 故障树:如何选择抓取方式

堆转储抓取决策树 怀疑 LiveData Observer 泄漏 已集成 LeakCanary ? 是 等待 LeakCanary 通知 点击后查看 LeakTrace 否 使用 AS Profiler 手动 Dump Force GC → Dump Java heap 获得 .hprof 文件 MAT 深度分析(引用链) AS Profiler 对象列表 选择建议 日常开发 → LeakCanary;复现定位 → AS Profiler;深度分析 → MAT

2.7 堆转储采集排查表

#检查项完成与否
1确保触发泄漏操作前已执行 GC(排除软/弱引用)□
2Dump 时机:泄漏场景结束后 1-3 秒内(避免二次重建干扰)□
3若使用 LeakCanary:确认通知出现且 LeakTrace 包含目标类□
4若使用 MAT:确认已通过 hprof-conv 转换为标准格式□
5检查 HPROF 中目标 Activity 的实例数是否为 0(正常)或 >0(泄漏)□
6保存原始 .hprof 文件用于后续对比或分享□

2.8 常见陷阱与最佳实践

  • 陷阱:在低端设备上 Dump HPROF 可能导致 ANR(Application Not Responding)。建议在 debug 构建中使用,并关闭所有非必要后台任务。
  • 陷阱:AS Profiler 的 Dump 默认不包含 Android 系统对象(如 ViewRootImpl),如需分析系统引用需勾选 Include native objects。
  • 最佳实践:每次 Dump 前先记录当前 Fragment / Activity 数量(可通过 adb shell dumpsys activity activities | grep mResumedActivity 获取)便于对照。
  • 最佳实践:当使用 LeakCanary 发现泄漏但 LeakTrace 不够清晰时,保存其导出的 .hprof 并用 MAT 二次分析,可获取更精准的 GC Root 路径。
经验法则:如果怀疑 LiveData Observer 泄漏,使用 LeakCanary 时选中 Lifecycle 过滤条件(在 LeakCanary 2.12 以上版本中会自动标记与 Lifecycle 相关的引用)。若该 Observer 持有 Activity 引用,LeakTrace 将明确显示链路,无需手动翻找。

掌握这三种工具的抓取方式后,下一步将进入 原因定位 环节——从堆转储中提取具体的引用路径,判断究竟是 setValue() 后未释放、还是 observeForever() 未被移除导致。