
文章插图
打开左上角的直方图 , 我们可以看到一个类列表 , 输入我们想搜索的类 , 就可以看到它的实例数 。

文章插图
我们右键 MemoryLeakActivity 类 , 选择 List Objects > with incoming references 查看这个 Activity 的实例 。
点击后 , 我们能看到一个实例列表 , 再右键其中一个实例 , 选择 Path to GC Roots > with all references 查看该实例被谁引用了 , 导致无法回收 。

文章插图
【探索 Android 内存优化方法】选择 with all references 后 , 我们可以看到该实例被静态对象 sCallbacks 持有 , 导致无法被释放 。

文章插图
这样就完成了一次内存泄漏的分析 。
11. 什么是 LeakCanary?11.1 LeakCanary 简介
如果使用 MAT 来分析内存问题 , 会有一些难度 , 而且效率也不是很高 。
为了能迅速发现内存泄漏 , Square 公司基于 MAT 开源了 LeakCanary 。
LeakCanary 是一个内存泄漏检测框架 。
11.2 LeakCanary 原理
- 检测保留的实例 LeakCanary 是基于 LeakSentry 开发的 , LeakSentry 会 hook Android 声明周期 , 并且会自动检测当 Activity 或 Fragment 被销毁时 , 它们的实例是否被回收了 。销毁的实例会传给 RefWatcher , RefWatcher 会持有它们的弱引用 。你也可以观察所有不再需要的实例 , 比如一个不再使用的 View , 不再使用的 Presenter 等 。如果等待了 5 秒 , 并且 GC 触发了之后 , 弱引用还没有被清理 , 那么 RefWatcher 观察的实例就可能处于内存泄漏状态了 。
- 堆转储 当保留实例(Retained Instance)的数量达到了一个阈值 , LeakCanary 会进行堆转储 , 并把数据放进 hprof 文件中 。当 App 可见时 , 这个阈值是 5 个保留实例 , 当 App 不可见时 , 这个阈值是 1 个保留实例 。
- 泄漏踪迹 LeakCanary 会解析 hprof 文件 , 并且找出导致 GC 无法回收实例的引用链 , 这也就是泄漏踪迹(Leak Trace) 。泄漏踪迹也叫最短强引用路径 , 这个路径是 GC Roots 到实例的路径 。
- 泄漏分组 当有两个泄漏分析结果相同时 , LeakCanary 会根据子引用链来判断它们是否是同一个原因导致的 , 如果是的话 , LeakCanary 会把它们归为同一组 , 以免重复显示同样的泄漏信息 。
- 添加依赖 dependencies { // 使用 debugImplementation 是因为 LeakCanary 一般不用于发布版本 debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-3' }
- 监控特定对象 // 1. 在 Application 中定义一个 RefWatcher 的静态变量 companion object { val refWatcher = LeakSentry.refWatcher } // 2. 使用 RefWatcher 监控该对象 MyApplication.refWatcher.watch(object);
- 配置监控选项private fun initLeakCanary { LeakSentry.config = LeakSentry.config.copy(watchActivities = false) }
- 添加依赖dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3' // 只有在你使用了 support library fragments 的时候才需要下面这一项 debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3' }
- 初始化 LeakCanarypublic class MyApplication extends Application { @Override public void onCreate { super.onCreate; // 不需要再 LeakCanary 用来做堆分析的进程中初始化 LeakCanary if (!LeakCanary.isInAnalyzerProcess(this)) { LeakCanary.install(this); return; } } }
- 监控特定对象// 1. 在 Application 中定义一个获取 RefWatcher 的静态方法 public static RefWatcher getRefWatcher() { return LeakCanary.installedRefWatcher; } // 2. 使用 RefWatcher 监控该对象 MyApplication.getRefWatcher.watch(object);
- 配置监控选项public class MyApplication extends Application { private void installLeakCanary { RefWatcher refWatcher = LeakCanary.refWatcher(this) .watchActivities(false) .buildAndInstall; } }
推荐阅读
- Java对象的内存分配过程是如何保证线程安全的?
- redis内存使用分析
- 中国茶路文化遗产保护与开发探索以湖南省为例
- 厉害了华为!先于美国禁令建立内存芯片库,存量能安然度过2020年
- 电商网站架构探索之SOA
- Redis内存又不够用了?教你几种集群方案轻松甩掉存储难题
- 谷歌|首发Android 13!谷歌Pixel 7 Pro渲染图曝光:后摄神似iPhone 14 Pro感叹号挖孔
- 群探索者的努力让茶馆成为传播茶文化的前沿阵地
- 手机内存不够?教你6招,立马多出几个G
- CPU,显卡,内存等硬件的频率是啥
