LeakCanary,26分钟从入门到驾驭

简述

在品质优化中,内存是2个只可以聊的话题;但是内存泄漏,突显已经改为内存优化的二个重量级的方向。当前流行的内存泄漏分析工具中,不得不提的就是LeakCanary框架;那是一个合龙方便,
使用便利,配置超级不难的框架,完毕的法力却是极为强大的。


不骗你,真的,使用就是如此简单 ?!

1. 您需求加上到安插的只有这几个

dependencies {

debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.3’

releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.3’

}

2. 你势必须要开始化一下,当然, 推荐在Application中

public class MyApplicationextends Application {

        @Override

        public void onCreate() {

                super.onCreate();

                LeakCanary.install(this);

                }

      }

3.
什么样?你还在下一步?已经终止了!通过以上配置,你就足以轻松使用LeakCanary检测内存泄漏了

   
关于LeakCanary的事无巨细使用教程,指出去看:LeakCanary华语使用表明


闲谈截止,我想你们来自然不是看本人那一个废话的,那么将来跻身正题!本篇大家所想的,就是LeakCanary为啥可以那样神奇,它是怎么检测内存泄漏的?上面大家解开谜题!


《LeakCanary原理》  大旨类分析 

01    LeakCanary                                        源码解析

02    LeakCanary   
                                    SDK提供类

03    DisplayLeakActivity  
                        内存泄漏的查阅页面

04    HeapAnalyzerService                         内存堆分析服务,
为了保险App进度不会就此受影响变慢&内存溢出,运维于独立的历程

05    HeapAnalyzer  
                                  解析由Ref沃特cher生成的堆转储音讯,
验证内存泄漏是或不是实际存在

06    HeapDump  
                                       堆转储音信类,存储堆转储的连锁音信

07    ServiceHeapDumpListener  
             三个监听,包蕴了打开分析的艺术

08    RefWatcher  
                                        骨干类, 翻译自官方:
检测不可达引用(只怕地),当发现不行达引用时,它会接触
 
                                                                       HeapDumper(堆音信转储)

09    ActivityRefWatcher 
                             Activity引用检测,
包含了Activity生命周期的监听执行与甘休

透过上述列表,让我们对LeakCanary框架的最首要类有个大致的刺探,并根据上述列表,对这些框架的大体成效有2个模糊的推断。


漫无目标的看源码,很不难迷失在空旷的Code
Sea中,无论是看源码,还是接手外人的门类,都以那般;由此,带着难题与目标性来看这个复杂的事物是很有必不可少的,也使得大家阅读功用大大升高;想要精通LeakCanary,大家最大的迷惑是怎么,作者列出来,看看是与您不约而同。

Question1:   
在Application中初步化之后,它是哪些检测全体的Activity页面的 ?

Question2:    内存泄漏的论断条件是何等 ?
检测内存泄漏的体制原理是何许?

Question3:    检测出内存泄漏后,它又是什么样变化泄漏音讯的?
内存泄漏的出口轨迹是怎么得到的?

回溯一下以此框架,其实大家想领会的编制不外乎三:

  1. 内存泄漏的检测机制

  2. 内存泄漏的判定机制

  3. 内存泄漏的轨道生成机制

大家会在源码分析最终,依次回答上述的几个难题,只怕在阅读源码此前,我们先要对内存泄漏做一些基础概念与原理的了解。


什么是内存泄漏(MemoryLeak)?

世家对这几个定义应该不生疏吧,当我们应用3个Bitmap,使用形成后,没有recycle回收;当我们拔取Handler,
在Activity销毁时并未拍卖;当大家运用Cursor,最后没有close并置空;以上那个都会促成一定水平上的内存泄漏难题。那么,什么是内存泄漏?

内存泄漏(Memory
Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或不可以自由,造成系统内存的浪费,导致程序运维速度放慢甚至系统崩溃等严重后果。

以上是百度宏观的表明,统计下为:内存泄漏是不采纳或用完的内存,因为一些原因无法回收,造成的一种内存浪费;内存泄漏的精神是内存浪费。以个体知道来表达,通俗一点就是

  1. GC回收的对象必须是当前并未其他引用的靶子

2.当目标在采纳形成后(对大家而言已经是废物对象了),
大家从不自由该目的的引用,导致GC不能够回收该对象而继续占据内存

3.破烂对象依旧占据内存,那块内存空间便浪费了

内存泄漏与内存溢出的不同是怎么着?

从名称来看,一个泄漏,一个溢出,其实很好明白。

内存泄漏
垃圾对象还是占据内存,如水龙头的败露,水自然是属于基本的,
然而水龙头没关紧,那么泄漏到了水池;再来看内存,内存本来应             
     
 该被回收,但是如故在内存堆中;计算一下就是内存存在于不应该存在的地点(没用的地点)

内存溢出
内存占用达到最大值,当需求分配内存时,已经远非内存可以分配了,就是溢出;依然以水池为例,
水池的水一旦满了,那么一旦继                     
续须求从水龙头流水的话,水就会溢出。统计一下就是,内存的分配超出最大阀值,导致了一种尤其

领悟了双面的定义,那么双方有何关系啊?

内存的溢出是内存分配达到了最大值,而内存泄漏是没用内存充斥了内存堆;由此内存泄漏是导致内存溢出的罪魁之一,而且是很大的罪魁;因为内存分配完后,哪怕占用再大,也会回收,而泄漏的内存则不然;当清理掉无用内存后,内存溢出的阀值也会相应大跌。


JVM怎样判定壹个目的是污物对象?

该难点也即垃圾对象搜索算法,JVM拔取图论的可达遍历算法来判断3个对象是或不是是垃圾对象,
倘使对象A是可达的,则以为该对象是被引用的,GC不会回收;若是目标A大概块B(七个对象引用组成的对象块)是不可达的,那么该目的大概块则判定是不可达的垃圾堆对象,GC会回收。


如上科普的多少个小知识:1) 内存泄漏  2) JVM搜索算法
是读书LeakCanary源码的底子,有助于源码的驾驭与回想。好了,下边来看一下LeakCanary的源码,看看LeakCanary是怎么工作的啊!

既然LeakCanary的开端化是从install()早先的,那么从init开头看

遥想一下核心类模块可知,内存分析模块是在单身进度中执行的,这么设计是为着保证内存分析进程不会对App进度造成悲伤的震慑,如使App进度变慢或造成out
of Memory难题等。由此

首先步: 判断APP进程与内存分析进度是或不是属于同一进度;假诺是,
则再次来到空的Ref沃特cher DISABLED;假使不是,往下走,看第1步

是还是不是与分析进程是同三个, isInAnalyzerProcess

与分析进程一致,重返八个空的DISABLED

第①步: enableDisplayLeakActivity 开启展现内存泄漏音讯的页面

调用了setEnabled,记住参数DisplayLeakActivity就是翻开泄漏的页面,enable传true,开启Activity组件

那些主意的职能是设置四大组件开启或剥夺,从上图传的参数看,是翻开了翻看内存泄漏的页面

其三步:起初化三个ServiceHeapDumpListener,这是2个敞开分析的接口完毕类,类中定义了analyze方法,用于开启二个DisplayLeakService服务,从名字就足以见见,那是三个来得内存泄漏的拉扯服务

看注释,这几个服务的功效是分析HeapDump,写入二个记下文件,并弹出壹个Notification

第④步:早先化七个沃特cher, Ref沃特cher和ActivityRef沃特cher.
那多少个沃特cher的功能分别为分析内存泄漏与监听Activity生命周期

ActivityRef沃特cher监听Activity生命周期,在初阶化时初步监听Activity生命周期(watchActivities)

watchActivities中登记了装有Activity的生命周期统一监听;onActiityDestroy会在onDestroy时实施,执行watch,检测内存泄漏

因此上述代码分析,大家可以得出第三个难题的答案。LeakCanary通过ApplicationContext统一登记监听的主意,来监督全部的Activity生命周期,并在Activity的onDestroy时,执行RefWatcher的watch方法,该办法的功效就是检测本页面内是还是不是存在内存泄漏难点。


下面我们继续来分析中央类Ref沃特cher中的源码,检测机制的主干逻辑便在Ref沃特cher中;相信阅读完那一个类后,首个难题的答案便活灵活现了。

既是想弄驾驭Ref沃特cher做了哪些,那么先来看一下官方的解释

监听只怕不可达的引用,当RefWatcher判定三个引用大概不足达后,会触发HeapDumper(堆转储)

从地点图可以看出官方的解释。
Ref沃特cher是2个引用检测类,它会监听只怕会产出泄漏(不可达)的靶子引用,倘使发现该引用或然是泄漏,那么会将它的音信搜集起来(HeapDumper).

从Ref沃特cher源码来看,大旨措施紧要有三个: watch()
和 ensureGone()。若是大家想单独监听某块代码,如fragment或View等,大家须要手动去调用watch()来检测;因为地方讲过,默许的watch()仅执行于Activity的Destroy时。watch()是大家间接调用的法门,ensureGone()则是实际哪些处理了,上面大家来看一下 

watch 检测中央措施

上图为watch()的源码, 我们先来看一下合法的诠释

监听提供的引用,检查该引用是还是不是足以被回收。那么些法子是非阻塞的,因为检测效用是在Executor中的异步线程执行的

从上述源码可以看看,watch里面只是履行了迟早的准备干活,如判空(checkNotNull),
为各样引用生成贰个唯一的key,
开始化KeyedWeakReference;关键代码依然在watchExecutor中异步执行。引用检测是在异步执行的,因而这一个历程不会卡住线程。

检测宗旨代码 gone()判定WeakReference中是还是不是包罗当前援引

以上是检测的基本代码已毕,从源码可以看看,检测的流程:

1) 移除不可达引用,要是当前引述不存在了,则不继续执行

2) 手动触发GC操作,gcTrigger中封装了gc操作的代码 

3) 再度移除不可达引用,如果引用不设有了,则不继续执行

4) 假若三回判定都未曾被回收,则始于分析这些引用,最平生成HeapDump音信

小结一下规律:

1.
弱引用与ReferenceQueue联合使用,若是弱引用关联的对象被回收,则会把那些弱引用参加到ReferenceQueue中;通过那个规律,可以看出removeWeaklyReachableReferences()执行后,会对应除去KeyedWeakReference的数额。假诺那几个引用继续存在,那么就声明没有被回收。

2.
为了确保最大担保的判断是或不是被回收,一共执行了三遍回收判定,包涵几反击动GC后的回收判定。一遍都没有被回收,很大程度上证实了那些目的的内存被泄露了,但并不大概100%保险;由此LeakCanary是存在极小程度的误差的。

地点的代码,计算下流程就是

认清是否回收(KeyedWeakReference是或不是留存该引用), Y -> 退出, N
-> 向下举行

手动触发GC

判断是或不是回收, Y -> 退出, N-> 向下举行

一回未被回收,则分析引用处境:

1) humpHeap :  这些点子是生成二个文件,来保存内存分析信息 

2) analyze: 执行分析

通过上述的代码分析,第3个难题的答案已经浮出水面了吧!


接下去分析内存泄漏轨迹的变更~

最终的调用,是在Ref沃特cher中的ensureGone()中的最终,如图

浅析最后调用,在ensureGone()中

很显明,走的是heapdumpListener中的analyze方法,继续追踪heapdumpListener是在LeakCanary起始化的时候初叶化并传到RefWatcher的,如图

在install中初阶化并传播RefWatcher

开辟进去ServiceHeapDumpListener,看其中完毕,如图

ServiceHeapDumpListener中的analyze

调用了HeapAnalyzerService,在单独的经过中开展分析,如图 

HeapAnalyzerService分析进度

HeapAnalyzerService中通过HeapAnalyzer来进展具体的辨析,查看HeapAnalyzer源码,如图

HeapAnalyzer

拓展分析时,调用了openSnapshot方法,里面用到了SnapshotFactory

org.eclipse.mat

从上图可以看到,那一个本子的LeakCanary采取了MAT对内存消息进行剖析,并扭转结果。其中在条分缕析时,分为findLeakingReference与findLeakTrace来查找泄漏的引用与轨道,依照GCRoot开端按树形结构依次指出当前援引的轨道消息。


经过上述分析,最终得出的结果为:

1. Activity检测机制是何许?

答:
通过application.registerActivityLifecycleCallbacks来绑定Activity生命周期的监听,从而监控所有Activity;
在Activity执行onDestroy时,开头检测当前页面是不是存在内存泄漏,并分析结果。因而,固然想要在不相同的地点都须求检测是或不是留存内存泄漏,要求手动添加。

2. 内存泄漏检测机制是什么样?

答:
KeyedWeakReference与ReferenceQueue联合利用,在弱引用关联的靶子被回收后,会将引用添加到ReferenceQueue;清空后,可以根据是或不是两次三番含有该引用来判断是或不是被回收;判定回收,
手动GC,
再次判定回收,采取双重判定来保障当前引用是不是被回收的景色不错;若是一回都未回收,则规定为泄漏对象。

3. 内存泄漏轨迹的更动进程 ?

答: 该版本采纳eclipse.Mat来分析泄漏详细,从GCRoot开端逐渐转移引用轨迹。

通过整篇小说分析,你还在质疑么?