泄漏证据采集:使用 Android Studio Profiler 抓取堆转储

3.1 堆转储在泄漏排查中的定位

堆转储(Heap Dump)是内存泄漏排查的核心证据来源。它记录应用进程中所有存活对象的类型、大小、引用链,能直接暴露本应被回收却仍被 GlobalScope 等长生命周期对象持有的实例。本课程第 3 章在“现象识别”之后执行数据采集,目的是将“内存持续增长”这一症状转化为可供分析的快照证据。

采集原则:堆转储应当在泄漏现象最明显的时刻抓取——即“内存上升后GC无法降回基线”的峰值点。过早抓取会漏掉泄漏对象,过晚抓取则因OOM崩溃而无法获取完整现场。

3.2 堆转储采集操作步骤

以下步骤适用于 Android Studio 4.2 及以上版本(基于 Coroutine 场景需注意 Profiler 版本对 Kotlin 协程的支持):

  1. 选择目标进程:在 Android Studio 底部点击 Profiler 窗口,选择“Memory”视图,确认已连接设备/模拟器上目标应用的进程。
  2. 切换 Memory 面板:点击 Memory 时间线选项卡,等待图表开始绘制内存使用量、Java堆、Native堆等曲线。
  3. 触发可疑操作:在应用内多次执行第 2 章中发现的泄漏路径(如反复打开/关闭某个 Activity 或频繁创建协程任务)。
  4. 发起 GC:点击 Profiler Memory 面板左侧的 Force GC 按钮(垃圾桶图标),触发一次手动垃圾回收,观察内存曲线是否下降。
  5. 抓取堆转储:在 GC 后内存仍高于基线约 2-3 MB 时,立即点击 Dump Java Heap 按钮(照相机图标)。等待 Profiler 完成堆快照生成。
  6. 保存文件:生成的堆转储以 .hprof 格式出现在 Profiler 右侧的 Snapshots 列表中。右键选择 Export to file… 保存到本地目录,便于后续离线分析。
// 通过 ADB 命令行也可触发堆转储(适用于自动化采集)  
adb shell am dumpheap <process_id> /data/local/tmp/dump.hprof  
adb pull /data/local/tmp/dump.hprof ./heap_dumps/

3.3 表格:不同内存采集方式的对比

采集方式作用域对性能影响能否发现泄漏推荐场景
Heap Dump(堆转储)Java/Kotlin 堆中所有对象较大(暂停应用 200-500ms)能,直接展示引用链泄漏定位、引用链分析
Allocation Tracking记录对象分配栈中等(部分性能开销)间接,需配合 Heap Dump定位高频分配点
Live Allocation(API 29+)无暂停采样跟踪小可观察存活对象变化实时监控内存波动

3.4 抓取时刻的判断规则

判断规则表:何时抓取堆转储最有效?
  • 规则 A(峰值抓取):手动 GC 后,内存下降幅度 ≤ 总增长量的 30%,且仍高于初始基线 2MB 以上 → 立即抓取。
  • 规则 B(重复抓取):至少连续抓取 2 次堆转储,间隔执行 3-4 次泄漏操作,对比两次快照中相同对象的实例数量是否增加。
  • 规则 C(避开干扰):抓取前暂停后台定时任务(如网络轮询、动画),避免临时对象污染快照。
  • 规则 D(异常捕获):若应用在内存峰值后 OOM 崩溃,使用 android:debuggable=true 并在 Application.onCreate() 中通过 android.os.Debug.dumpHprofData() 在崩溃前自动 dump。

3.5 内联 SVG:堆转储采集流程

堆转储采集流程 1. 打开Memory面板 2. 触发泄漏路径 3. 执行Force GC 判断:内存是否下降 4. 点击 Dump Heap 5. 导出.hprof文件 否 是 关键:当 GC 后内存无法回落到基线时,泄漏源大概率还在堆中,此时 dump 最有效

3.6 常见陷阱与规避

避坑清单:
  • 单次 dump 误判:泄漏对象可能因 GC 根临时变化而未被识别,务必在不同泄漏阶段连续抓取 2-3 次。
  • 忽略 Native 堆:GlobalScope 本身是 Java 对象,但其关联的 Continuation 可能持有 Native 引用(如 JNI 回调),在 Dump Java Heap 后额外关注 Native Memory 面板。
  • 快照过大:若堆转储文件超过 200 MB,分析工具(如 MAT)可能卡顿。此时先通过 Force GC 清理临时对象,或使用 Android Studio 内置的 Heap Viewer 快速筛选大对象。
  • 遗漏协程上下文:Kotlin 协程的 Job、Continuation 对象在堆转储中可能以 kotlin.coroutines.jvm.internal.BaseContinuationImpl 形式出现,需在分析时将过滤条件设为该基类。

完成堆转储采集后,下一步将进入第 4 章:原因定位——通过 MAT 或 Android Studio 的引用树分析,找出 GlobalScope 具体持有的泄漏对象及其 GC Root 路径。