leakCanery 是检测Android内存泄漏的工具
Android中内存泄漏的本质:Android (或 JVM)的内存泄露:短⽣命周期的对象被⻓⽣命周期的对象持有, 从⽽导致短⽣命周 期的对象不能被释放
1. 第一步:标记 “待验证对象”(Activity)
当 Activity 执行 onDestroy() 时,LeakCanary 认为它 “应该进入可回收状态”,
为这个 Activity 创建 KeyedWeakReference(绑定 ReferenceQueue)
第二步:触发 GC,让虚拟机做 “可达性分析”
LeakCanary 主动调用 Runtime.getRuntime().gc(),触发虚拟机执行可达性分析(GC 的核心工作):
- 虚拟机从 GC Roots(静态变量、主线程栈帧、JNI 引用等)出发,遍历所有对象的引用链;
- 如果遍历后发现:没有任何强引用指向这个 Activity → 判定 Activity 为 “不可达”,标记为 “可回收”;
- 如果有强引用(比如单例持有 Activity)→ 判定 Activity 为 “可达”,标记为 “不可回收”。
第三步:通过 “弱引用是否入队” 验证结果
虚拟机完成可达性分析后,会按规则处理弱引用:
-
✅ 如果 Activity 不可达(可回收):
虚拟机先销毁 Activity,释放内存,同时把绑定的
KeyedWeakReference加入 ReferenceQueue(这是虚拟机的 “通知行为”);LeakCanary 检查队列,发现这个弱引用 → 判定 “Activity 已被回收,其内部成员变量也跟着被回收了”。
-
❌ 如果 Activity 可达(不可回收):
虚拟机不会销毁 Activity,也不会把弱引用加入队列;
LeakCanary 检查队列,没找到这个弱引用 → 判定 “Activity 还被强引用持有,无法回收,其内部成员变量也跟着泄漏”。
三、关键补充:LeakCanary 如何定位成员变量的泄漏?
当判定 Activity 泄漏后,LeakCanary 会通过堆快照(.hprof)做两件事:
- 从 GC Roots 出发,找到指向 Activity 的强引用链(比如 “静态单例 → Activity.mPresenter → Activity”);
- 解析堆快照中的对象结构,展示 Activity 内部哪些成员变量被连带引用(比如 mPresenter 被单例持有,导致整个 Activity 无法回收)。
简单说:LeakCanary 先通过弱引用验证 Activity 是否泄漏,再通过堆分析找到泄漏的 “罪魁祸首”(可能是某个成员变量被外部强引用)。
垃圾回收机制
垃圾回收机制分为「引⽤计数法」和「可达性分析法」
引⽤计数法:⽤⼀个计数器记录⼀个对象被引⽤的次数,如果引⽤的次数被减少到 0 那么说 明这个对象是垃圾 对象。 都是引⽤计数(引⽤计数有循环引⽤的问题)
**可达性分析法:Jvm 通过⼀些 GC Roots 向下搜索,如果可以被 Gc Roots 引⽤到的对象,说明 这个对象不是垃圾 对象,反之这个对象就算互相引⽤了也是垃圾对象 那些对象 会被作为 GC Roots 呢
**
在线程栈中的局部变量,也就是正在被调⽤的⽅法,它⾥⾯的参数和局部变 量
存活的线程对象
JNI 的引⽤
Class 对象,因为 Android 加载 Class 后不会卸载 Class
引⽤类型的静态变量
四⼤引⽤:
强⼀点的引⽤: 强引⽤——不会被垃圾回收
弱⼀点的引⽤:
弱引⽤——可以通过 get() 获得引⽤对象,会被垃圾回收
软引⽤——可以通过 get() 获得引⽤对象,内存不⾜会被垃圾回收
虚引⽤——不能通过 get() 获得引⽤对象,会被垃圾回收