LeakCanary

一、基本用法

1. 依赖配置

dependencies {
  // 最新版本(以2.x为例)
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}

2. 自动安装(2.x版本)

2.x版本默认自动安装,无需手动初始化:

  • 通过ContentProvider自动初始化

  • debug构建变体生效

  • 应用启动时自动开始监视

1.x版本需手动初始化(已过时):

class MyApplication : Application() {
  override fun onCreate() {
    super.onCreate()
    if (LeakCanary.isInAnalyzerProcess(this)) return
    LeakCanary.install(this)
  }
}

3. 检测范围

默认自动监视:

  • 销毁的Activity

  • 销毁的FragmentView(通过androidx.fragment集成)

  • 清除的ViewModel

4. 手动监视对象

5. 测试中检测内存泄漏

工作原理:

  1. RefWatcher.watch() 创建一个 KeyedWeakReference 到要被监控的对象。

  2. 然后在后台线程检查引用是否被清除,如果没有,调用GC。

  3. 如果引用还是未被清除,把 heap 内存 dump 到 APP 对应的文件系统中的一个 .hprof 文件中。

  4. 在另外一个进程中的 HeapAnalyzerService 有一个 HeapAnalyzer 使用HAHA 解析这个文件。

  5. 得益于唯一的 reference key, HeapAnalyzer 找到 KeyedWeakReference,定位内存泄漏。

  6. HeapAnalyzer 计算 到 GC roots 的最短强引用路径,并确定是否是泄漏。如果是的话,建立导致泄漏的引用链。

  7. 引用链传递到 APP 进程中的 DisplayLeakService, 并以通知的形式展示出来。

二、核心架构与源码分析

1. 整体架构

2. 核心流程

步骤1:对象监视(ObjectWatcher)

步骤2:触发GC并检查

步骤3:堆转储(Heap Dump)

步骤4:HPROF文件分析

3. 关键类解析

1. AppWatcher

2. KeyedWeakReference

3. InternalLeakCanary

4. 泄漏链分析算法

LeakCanary使用最短强引用路径算法:

GC Roots查找:从GC Root开始查找

支配树构建:计算对象间的支配关系

最短路径计算:找出泄漏对象到GC Root的最短路径

去重优化:合并相同泄漏模式

5. 内存优化机制

1. 阈值控制

2. 避免频繁转储

相同泄漏模式去重

最小间隔时间限制(默认1分钟)

磁盘空间检查

3. 分析进程隔离

独立进程(:leakcanary)进行分析

避免影响主进程性能

可独立配置堆大小

三、高级配置

1. 自定义配置

2. 忽略特定泄漏

3. 自定义分析结果处理

四、核心设计思想

1. 非侵入式监控

基于ActivityLifecycleCallbacksFragmentLifecycleCallbacks

无源码侵入,仅依赖添加

2. 精准触发机制

延迟检测(默认5秒)

手动触发GC

阈值控制避免误报

3. 性能平衡

主进程仅监控,不分析

分析在独立进程进行

智能去重,避免重复分析

4. 可扩展架构

插件化设计

可自定义ReferenceMatcher

可替换HeapDumperHeapAnalyzer

五、最佳实践

仅Debug版本启用:避免生产环境性能影响

设置合理阈值:避免频繁触发堆转储

及时修复泄漏:关注"Application Leak"(应用泄漏)

忽略已知泄漏:第三方库已知问题可配置忽略

结合CI/CD:在自动化测试中集成LeakCanary检查

总结

LeakCanary通过弱引用监控 + 延迟GC检查 + 独立进程分析的架构,在保证检测准确性的同时最大限度减少对应用性能的影响。其核心价值在于:

自动化:自动监控、自动分析、自动报告

准确性:通过实际堆转储分析,避免误报

可操作性:提供完整的泄漏引用链,便于定位问题

性能友好:主进程轻量监控,复杂分析在独立进程进行

Last updated