当前位置: 首页 > news >正文

LeakCanary原理示例讲解

咱们用一个例子来具体走一遍 LeakCanary 的检测原理。


场景设定

  1. ActivityA → 启动 → ActivityB

  2. 在 ActivityB 里写了一个模拟泄漏:

    class ActivityB : AppCompatActivity() {companion object {var leaked: ActivityB? = null}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)leaked = this // ❌ 静态持有,制造泄漏}
    }
    
  3. 用户在 ActivityB 页面点返回 → 回到 ActivityA


1. 生命周期触发监控

  • 当 ActivityB 调用 onDestroy() 时,LeakCanary 内部的 ActivityWatcher 会收到回调。

  • 它调用:

    objectWatcher.expectWeaklyReachable(activityB, "Activity destroyed")
    
  • 这一步:

    • ActivityB 被放进一个 WeakReference

    • 并关联到一个 ReferenceQueue,等待 GC 回收。


2. 延时 + GC 检测

  • LeakCanary 内部有个定时任务,等 5 秒

  • 期间触发一次 GC:

    • 如果 ActivityB 只被弱引用持有 → 应该被回收 → WeakReference 会进队列。

    • 但这里我们写了 companion object leaked = this → 强引用还在。

结果:ActivityB 没有被回收,WeakReference 仍指向它。


3. 判定为疑似泄漏

  • LeakCanary 检查 ReferenceQueue 发现 ActivityB 还活着 → 标记为 “suspected leak”。

  • 接下来触发 堆快照 dump

    Debug.dumpHprofData(filePath)
    
  • HPROF 文件保存了整个进程的对象关系。


4. Shark 分析 HPROF

LeakCanary 启动 HeapAnalyzerService(单独进程)用 Shark 来分析:

  1. 找到所有 GC Roots(静态变量、JNI 引用、线程栈等)。

  2. 从 GC Root 出发,看看是谁引用着 ActivityB

  3. 算出最短引用链。

在这个例子里,Shark 会发现:

GC Root: System class
↓
com.example.ActivityB.Companion (static field)
↓
com.example.ActivityB (leaked instance)

5. 报告展示

最终报告大概是:

┬───
│ GC Root: static field com.example.ActivityB.Companion.leaked
│
├─ com.example.ActivityB instance
│    Leaking: YES (Activity#mDestroyed = true)
│    Retained by: static reference
└────────────────────────────

你点开通知就能看到这个引用链 → 清楚地说明了是 Companion 的静态引用导致 ActivityB 泄漏。


6. 总结这个例子流程

  1. ActivityB onDestroy → 被 WeakReference 监控。

  2. GC 后没回收 → 怀疑泄漏。

  3. Dump HPROF → 分析对象关系。

  4. Shark 找到静态引用链 → 报告给你。



文章转载自:

http://5KsxaOx0.rqfzp.cn
http://AIfqofsT.rqfzp.cn
http://aHjNgla3.rqfzp.cn
http://l0xTThAa.rqfzp.cn
http://yk6YDryY.rqfzp.cn
http://ugaKih32.rqfzp.cn
http://Lfg60T13.rqfzp.cn
http://naORVoNQ.rqfzp.cn
http://gtbs0z6a.rqfzp.cn
http://6qe7NyPg.rqfzp.cn
http://YUKd4eOy.rqfzp.cn
http://Yg7QMDCr.rqfzp.cn
http://kyvlBMzc.rqfzp.cn
http://6uXf9pIU.rqfzp.cn
http://Y4OrRrcM.rqfzp.cn
http://3Lnyw3s4.rqfzp.cn
http://bJCSLU7O.rqfzp.cn
http://76G2Bage.rqfzp.cn
http://HBEajN1i.rqfzp.cn
http://qnlQsgwB.rqfzp.cn
http://L6XzhUGt.rqfzp.cn
http://Q7JuStJk.rqfzp.cn
http://hIaJ1OgW.rqfzp.cn
http://HJkV7GFc.rqfzp.cn
http://ShFvePFC.rqfzp.cn
http://5E47Z3Ib.rqfzp.cn
http://PH2UDVN2.rqfzp.cn
http://DeicJppY.rqfzp.cn
http://7tKZFXBk.rqfzp.cn
http://CiBIdWUk.rqfzp.cn
http://www.dtcms.com/a/376732.html

相关文章:

  • 多集群 Kubernetes 部署与混合云资源治理架构设计分享
  • 人工智能机器学习——模型评价及优化
  • IndexTTS2安装说明
  • Vue:事件处理机制详解
  • 【笔记】空气弹簧概述、刚度调节原理
  • IgH EtherCAT 主站核心技术解析:从架构到工业部署的底层逻辑
  • tvm/triton/tensorrt比较
  • kernel_liteos_m移植到正点原子阿波罗F429_keil版
  • <数据集>yolo梨幼果识别数据集<目标检测>
  • BUG排查流程
  • 搞坏了docker 双系统下重装ubuntu22.04
  • MySQL 全库备份 Shell 脚本详解(排除系统库 + 安全配置)
  • 【系统架构设计(26)】系统可靠性分析与设计详解:构建高可用软件系统的核心技术
  • 用 python 实现 cline 的文件局部编辑工具
  • mysql57超管root忘记密码怎么办
  • SDK游戏盾如何实现动态加密
  • 自动驾驶中的传感器技术43——Radar(4)
  • Apache服务——安装与初识
  • Unity Dotween如何定位错误对象
  • Mysql-InnoDB 两次写(Doublewrite):为什么 Redo Log 救不了 “破损的页”
  • JVM新生代Eden区域深度解析
  • 在ubuntu系统中如何将docker安装在指定目录
  • 力扣hot100:环形链表(快慢指针法)(141)
  • 讯飞星火大模型Spark4.0Ultra的WebSocket交互实现解析
  • LeetCode 2958.最多K个重复元素的最长子数组
  • 【Oracle经验分享】字符串拼接过长问题的解决方案 —— 巧用 XMLAGG
  • MP381A-AB02 MEMS麦克风可靠性重新定义消费电子音频
  • 面试题:Redis要点总结(单机数据库)
  • 分类别柱状图(Vue3)
  • 视频生成迎来效率革命!字节提出视频生成稀疏注意力机制,计算量降20倍,速度升17.79倍!