美学原理LeakCanary,30分钟由入门到精通

简述

在性质优化中,内存是一个只好聊的话题;然而内存泄漏,显示就变成内存优化的一个重量级的大方向。当前兴的内存泄漏分析工具中,不得不提的饶是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  
                                  浅析由RefWatcher生成的积聚转储信息,
验证内存泄漏是否真正存在

06    HeapDump  
                                       堆转储信息类,存储堆转储的相干信息

07    ServiceHeapDumpListener  
             一个监听,包含了被分析的点子

08    RefWatcher  
                                        中心类, 翻译自官方:
检测不可及引用(可能地),当发现不行及引用时,它会触发
 
                                                                       HeapDumper(堆信息转储)

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

经过以上列表,让大家对LeakCanary框架的重要性类闹个大致的摸底,并冲以上列表,对这个框架的盖功能来一个模糊的猜想。


漫无目的的看源码,很容易迷失在宏阔的Code
Sea中,无论是看源码,还是接手别人的门类,都是如此;因此,带在问题以及目的性来拘禁这些复杂的事物是雅有必不可少之,也使我们看效率大大提高;想使了解LeakCanary,我们绝要命之疑惑是什么,我排出来,看看是跟公不约而同。

Question1:   
在Application中初始化之后,它是如何检测所有的Activity页面的 ?

Question2:    内存泄漏的判定条件是啊 ?
检测内存泄漏的机制原理是呀?

Question3:    检测出内存泄漏后,它又是怎么样转泄漏信息之?
内存泄漏的输出轨迹是怎抱的?

回溯一下这个框架,其实我们怀念询问之机制不外乎三:

  1. 内存泄漏的检测机制

  2. 内存泄漏的判断机制

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

俺们见面在源码分析最后,依次回答上述之老三只问题,可能当读书源码之前,我们事先使对内存泄漏做有基础概念与原理的喻。


好家伙是内存泄漏(MemoryLeak)?

世家对这概念应该无陌生吧,当我们下一个Bitmap,使用到位后,没有recycle回收;当我们采取Handler,
在Activity销毁时没拍卖;当我们应用Cursor,最后没有close并置空;以上这些还见面招一定程度上之内存泄漏问题。那么,什么是内存泄漏?

内存泄漏(Memory
Leak)是指程序中本身动态分配的积聚内存由于某种原因程序不释放或无法自由,造成系统内存的荒废,导致程序运行速度放慢甚至系统崩溃等严重后果。

如上是百度百科的诠释,总结下也:内存泄漏是不以要因此了的内存,因为一些原因无法回收,造成的同一栽内存浪费;内存泄漏的本来面目是内存浪费。以个体知道来诠释,通俗一点纵是

  1. GC回收的对象要是眼前从来不另外引用的目标

2.当对象在利用完后(对咱而言就是污物对象了),
我们从没自由该对象的援,导致GC不能够回收该目标要持续占有内存

3.废品对象依旧占据内存,这块内存空间就浪费了

内存泄漏和外存溢出底分别是呀?

自从名称来拘禁,一个泄露,一个溢起,其实大好掌握。

内存泄漏
垃圾对象还占据内存,如度把的透漏,水自然是属本的,
但是历届把没拖累紧,那么泄漏到了水池;再来拘禁内存,内存本来承诺             
     
 该叫回收,但是仍在内存堆中;总结一下便是内存存在于不拖欠是的地方(没因此的地方)

内存溢出
内存占用达到最好可怜价值,当得分配内存时,已经远非内存可以分配了,就是溢起;依旧以水池也例,
水池的度一旦满了,那么只要继                     
续需要从水龙头流水的语句,水就是会见漫起。总结一下虽是,内存的分红超出最老阀值,导致了同种怪

晓了两者的概念,那么双方有啊关系为?

内存的溢出起是内存分配达到了无限深价值,而内存泄漏是没用内存充斥了内存堆;因此内存泄漏是引致内存溢出底首恶之一,而且是死充分的元凶;因为内存分配了晚,哪怕占用再挺,也会见回收,而泄漏的内存则不然;当清理掉无用外存后,内存溢出底阀值也会相应降低。


JVM如何判断一个对象是垃圾对象?

该问题也便垃圾对象搜索算法,JVM采用图论的但是达到遍历算法来判断一个目标是否是废品对象,
如果对象A是可达的,则觉得该对象是给引述的,GC不会见回收;如果目标A或者块B(多单目标引用组成的靶子块)是不可达的,那么该对象或块则判定是不可达的废料对象,GC会回收。


如上大的有限独稍知识:1) 内存泄漏  2) JVM搜索算法
是阅读LeakCanary源码的基本功,有助于源码的明亮和记忆。好了,下面来拘禁一下LeakCanary的源码,看看LeakCanary是怎工作之吧!

既然LeakCanary的初始化是由install()开始之,那么自从init开始看

想起一下骨干类模块能,内存分析模块是于独立进程中执的,这么设计是以保内存分析过程未会见指向App进程造成消极的影响,如一旦App进程变慢或致out
of Memory问题等。因此

先是步: 判断APP进程和内存分析过程是否属同一进程;如果是,
则返回空的RefWatcher DISABLED;如果无是,往下活动,看第二步

是不是和分析过程是与一个, isInAnalyzerProcess

及分析过程同,返回一个拖欠的DISABLED

老二步: enableDisplayLeakActivity 开启显示内存泄漏信息的页面

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

以此艺术的来意是设置四深组件开启或剥夺,从达成图传的参数看,是打开了翻看内存泄漏的页面

老三步:初始化一个ServiceHeapDumpListener,这是一个拉开分析的接口实现类似,类吃定义了analyze方法,用于开启一个DisplayLeakService服务,从名字就可以看出,这是一个示内存泄漏的帮助服务

关押注释,这个服务之企图是分析HeapDump,写副一个记录文件,并弹来一个Notification

季步:初始化两单Watcher, RefWatcher和ActivityRefWatcher.
这片只Watcher的作用分别吗分析内存泄漏和监听Activity生命周期

ActivityRefWatcher监听Activity生命周期,在初始化时开始监听Activity生命周期(watchActivities)

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

通过以上代码分析,我们得以汲取第一单问题的答案。LeakCanary通过ApplicationContext统一登记监听的点子,来监督所有的Activity生命周期,并当Activity的onDestroy时,执行RefWatcher的watch方法,该办法的打算就是是检测本页面内是否有内存泄漏问题。


下我们后续来分析中心类RefWatcher中的源码,检测机制的为主逻辑就是以RefWatcher中;相信阅读了这个类似后,第二个问题之答案便呼之得来了。

既是想打明白RefWatcher做了哟,那么先来拘禁一下官方的诠释

监听可能不可达的援,当RefWatcher判定一个援可能不足及后,会触发HeapDumper(堆转储)

自上面图可以观看官方的讲。
RefWatcher是一个引用检测类,它见面监听可能会见起泄漏(不可达)的目标引用,如果发现该引用可能是泄漏,那么会用她的信搜集起来(HeapDumper).

由RefWatcher源码来拘禁,核心措施主要发生有限个: 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: 执行分析

经上述之代码分析,第二个问题的答案已显露出水面了吧!


紧接下分析内存泄漏轨迹的变通~

末段之调用,是在RefWatcher中的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开始逐渐扭转引用轨迹。

经过整篇文章分析,你还以疑惑么?