LeakCanary浅析

内存泄漏

内存不需要使用时,但是无法释放归还给系统,对于对象的引用无法及时释放,简单一句话,短生命周期的对象被长生命周期的对象持有了

常见的内存泄漏

  1. 被static修饰的变量的生命周期和应用程序的一样长,非静态内部类的对象赋值给了静态引用,(非静态的内部类会默认持有外部类的引用,导致外部类无法释放)
  2. 资源使用后没有关闭:文件流,数据库等
  3. 匿名内部类(给静态变量设置监听时,由于匿名内部类会持有Activity引用,static又持有匿名内部类引用)
  4. Handler 内存泄漏

初始化

在1.x 版本之中需要在application中手动初始化

在2.x 版本之中不需要自己初始化,他自己注册了一个contentProvider

contentProvider在application创建之后,在activity创建之前被创建,因此可以在contentProvider的oncreate方法中获取到applicationContext对象

测试发现其执行顺序

ContentProvider->onCreate() Application->onCreate() Activity->onCreate()

观察源码发现

ActivityThread中,创建Application对象之后会调用installContentProviders()安装属于当前进程,因此,一些需要在Application中初始化的操作可以放到ContentProvider中处理,这是一个很巧妙的解耦方式

这种方式虽然简化了开发人员的代码编写,但是对应用的启动冷启动速度会造成一定的影响,在编写SDK的时候还是应该提供初始化方法(有的时候可以延迟初始化来达到提升启动速度的目的)

至于为什么LeakCanary设置成这样,因为leakCanary只是在开发阶段使用的工具,在后续的release版本并不会加入,并不会造成影响

原理

Android里面常见的资源对象都有生命周期的回调,在某个对象不在需要回调时候会执行销毁的生命周期回调(例如Activity的onDestroy),执行之后说明我们的 activity 对象是需要回收的。

LeakCanary 就是在onDestroy的时候注册回调,把activity对象使用弱引用对象包装,并对该activity 生成一个唯一id,

why 用弱引用 ,因为弱引用里面包装的对象 在垃圾回收之前 弱引用对象会被加入到一个引用队列ReferenceQueue中, 然后以<id,WeakReference<activity>>的形式加入到一个map中(这个map可以当作一个可怀疑对象,怀疑这个对象有可能会发生内存泄漏),之后手动调用GC ,GC之后去ReferenceQueue找当前id 所对应的WeakReference是否存在,如果存在,则说明被回收了,并把map中的怀疑对象移除,否则,则说明发生了内存泄漏,之后导出堆文件进行分析

源码浅析

进入到MainProcessAppWatcherInstaller可以发现只实现了一个空壳的ContentProvider,只在oncreate方法里面进行了初始化工作

进入ManualyInstall方法中可以看到install一共有四个实现类,也就是可以监控Activity/Fragment/View/Service的内存泄漏

以activity为例,点进去可以看到注册了回调,registerActivityLifecycleCallBacks 注册之后可以监听所有的activity的生命周期回调

进入到expectWeaklyReachable 方法

标记1 处把引用队列清空

标记2处 包装activity 和key 的弱引用并在标记3 处加入map中(怀疑泄漏的对象)

进入 moveToRetained

这里的executor 就是把一个runnable 发送到了主线程的Looper中,并延迟5秒钟执行

之后又在子线程进入了checkRetainedObjects方法

之后主动调用GC ,并再次计算进行怀疑对象的移除

此时计算出怀疑数量之后在checkRetainedCount 方法中判断泄漏数量是否达到阈值,默认为5,达到阈值才dump内存,否则给出一个通知

dump通过Debug.dumpHprofData(heapDumpFile.absolutePath)来dump出 hprof文件,这个是AndroidSDK 自带的

之后LeakCanary会通过调用shark分析gcroot的最短路径得出其泄漏路径的trace,以前1.x版本用的分析库是haha,听说shark 分析时间会大幅度减少

相关推荐
Tans57 天前
LeakCanary 源码阅读笔记(四)
源码阅读·leakcanary
Just_Paranoid5 个月前
Android性能优化之内存泄漏优化(工具篇)
android·性能优化·leakcanary·mat·profiler
Lei活在当下9 个月前
LeakCanary源码解析
leakcanary
很好奇1 年前
【内存泄漏】图解 Android 内存泄漏
android·leakcanary
小海编码日记1 年前
从LeakCanary看Fragment生命周期监控
android·android jetpack·leakcanary
派大星不吃蟹1 年前
面试问到:LeakCanray 2.0为啥不需要在application里调install?
android·leakcanary