看本篇之前建议先看下JVM、Dalvik、ART【类的引用方式】一节,了解JVM的内存模型和GC的相关内容,为后面做铺垫
概述
LeakCanary的实现原理:利用了弱引用的性质观察对象状态,并联合ActivityLifecycleCallbacks获取对象被销毁的通知,如果对象通知已被销毁但对象的状态并未回收,则可判定对象逃逸
使用
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
// Optional, if you use support library fragments:
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
添加依赖
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
初始化配置
这里isInAnalyzerProcess是为了防止多进程导致Application多次调用onCreate造成LeakCanary的多次初始化
将debugImplementation、releaseImplementation换成implementation查看源码会发现LeakCanary只有在debug版本才会起作用,在
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
中LeakCanary.isInAnalyzerProcess(this)=false
而LeakCanary.install(this)=DISABLE
源码
源码主要有两大功能模块:监测对象、分析泄露,开始主菜前先来点甜品
进程操作
先来看看LeakCanary是如何判断进程的
LeakCanarypublic static volatile Boolean isInAnalyzerProcess;
唯一对象
监测对象
LeakCanary先创建了AndroidRefWatcherBuilder对象
AndroidRefWatcherBuilder调用父类方法heapDumpListener设置回调监听
excludedRefs方法用来排除安全的但会被认为非安全的引用,具体的内容在枚举类AndroidExcludedRefs中有声明这也是LeakCanary的价值所在,感谢开源
AndroidRefWatcherBuilder启用组件
因为LeakCanary并没有在项目AndroidManifest.xml中声明显示泄露路径的activity,因此需要通过以下方式声明activity
AndroidRefWatcherBuilder所启用的组件是查看泄露路径的DisplayLeakActivity
LeakCanaryInternals内部使用AsyncTask的默认线程池异步执行Runnable
LeakCanaryInternalsnewState:
- 不可用状态:COMPONENT_ENABLED_STATE_DISABLED
- 可用状态:COMPONENT_ENABLED_STATE_ENABLED
- 默认状态:COMPONENT_ENABLED_STATE_DEFAULT
flags:行为标签,值可以是DONT_KILL_APP或者0。 0说明杀死包含该组件的app
监控Activity
ActivityRefWatcher内部逻辑很简单,在Application上注册ActivityLifecycleCallbacks,每当activity被关闭回调onActivityDestroyed时,便让传入的refWatcher对象监控activity对象
监控Fragment
FragmentRefWatcher.Helper同样是在Application上注册ActivityLifecycleCallbacks,只不过监听的是onActivityCreated,每当activity创建FragmentRefWatcher对象便开始监控。
Android8.0以下默认是不监控的,需要添加依赖
// Optional, if you use support library fragments:
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
这也是框架功能扩展的设计模式
以8.0为例,扩展包类似
AndroidOFragmentRefWatcher在传入的activity对象上注册FragmentLifecycleCallbacks,当fragment对象销毁时让传入的refWatcher对象监控view和fragment对象
监控者RefWatcher
在监控Activity和Fragment的过程中,都是对象应该被销毁时让refWatcher监控,那就要看看它是如何监控的
AndroidRefWatcherBuilder通过构造者模式创建的RefWatcher对象
RefWatcher监控对象是理论上被回收的object,将传入的对象包装成KeyedWeakReference设置唯一uuid标识,同时记录此对象的uuid,这是一个弱引用对象继承自WeakReference
RefWatcher异步执行,检查监控对象是否回收
RefWatcher手动GC,判断监控对象是否被放入queue,放入则表示正常回收,否则表示对象逃逸需要分析dump文件查找引用链
分析泄露
DumpFile
RefWatcher反向查找,dumpfile来自heapDumper
RefWatcher RefWatcherBuilder RefWatcherBuilder AndroidRefWatcherBuilder而heapDumper是来自RefWatcherBuilder的子类AndroidRefWatcherBuilder重写的defaultHeapDumper返回的AndroidHeapDumper对象
AndroidHeapDumper可以看出dumpfile文件来自leakDirectoryProvider,通过Debug.dumpHprofData
将dump信息写入dumpfile文件
leakDirectoryProvider是DefaultLeakDirectoryProvider的对象,负责维护dumpfile
LeakDirectoryProvider实际LeakDirectoryProvider产生了空的dumpFile文件,还负责维护总dumpFile文件的数量
RefWatcherRefWatcher对象拿到了存有dump信息的文件,将其组装成存有dump信息、对象唯一uuid等信息的HeapDump对象,交由heapdumpListener分析
Analysis
RefWatcher RefWatcherBuilder AndroidRefWatcherBuilderheapdumpListener对象是ServiceHeapDumpListener类型
ServiceHeapDumpListener HeapAnalyzerService内部启动了HeapAnalyzerService服务,它是IntentService的子类
HeapAnalyzerService由HeapAnalyzer分析出result后交由AbstractAnalysisResultService
AbstractAnalysisResultService这里启动了前面传入的DisplayLeakService,通过重写父类AbstractAnalysisResultService方法onHeapAnalyzed
DisplayLeakService这里将分析结果交给最初启用的组件DisplayLeakActivity显示
HeapAnalyzer
实际的分析过程在HeapAnalyzer.checkForLeak方法中
HeapAnalyzer HeapAnalyzer HeapAnalyzer这里用了square的haha库分析hprof文件
找到逃逸对象及其引用链
网友评论