LeakCanary使用简介

来源:互联网 发布:碑文排版软件 编辑:程序博客网 时间:2024/05/22 04:41

这一篇博客主要记录一下LeakCanary的使用方式。

一、LeakCanary简介
目前,Java程序最常用的内存分析工具是MAT。
MAT的使用比较简单,但分析对应数据的步骤较为繁琐,结果也不够直观。

针对这个情况,Square公司为Android开发者,供了一个自动检测内存泄漏的工具,即LeakCanary。
LeakCanary被集成到Android工程后,一旦发现应用出现内存泄露问题,
就会主动弹出一个通知,然后在通知拉起的界面上,显示出问题的详细信息。

LeakCanary是一个开源工具,感兴趣的朋友可以研究一下它的源码,
由于我并没有深入分析过,因此此处仅结合网上的资料,简要记录一下它的原理。

1.1 发现潜在泄漏对象
LeakCanary被使用后,将会创建一个RefWatcher对象。

RefWatcher对象的watch方法被调用后,将会使用WeakReference引用Activity、Fragment等对象。
同时,RefWatcher会为这些对象生成唯一的Key值,然后将每个对象的Key、WeakReference与ReferenceQueue关联起来。
此外,LeakCanary会创建一个集合retainedKeys保存所有对象的Key值。

系统每次GC时,LeakCanary都可以扫描ReferenceQueue,
得到被释放对象的WeakReference(弱引用对象被释放后,对应的引用将被添加到ReferenceQueue中)。
然后,根据映射关系,LeakCanary得到WeakReference对应的Key值,
并将这些Key值从retainedKeys中移除。

于是,每次GC后,retainedKeys中剩余Key对应的对象,就是潜在的内存泄漏对象。

上述整个过程,基本思路如下图所示:

1.2 分析引用链
LeakCanary找到未被释放的对象后,必须分析该对象的引用关系,
才能确定该对象是否会导致内存泄漏。

为了完成这部分工作:LeakCanary会利用VMDebug与HAHA生成对象的最短引用链。

这一部分工作的依据是:VM 会有堆内各个对象的引用情况,并能以 hprof 文件导出。
HAHA作为square提供的Android 堆分析库,可以分析hprof文件生成Snapshot。
最终,LeakCanary利用Snapshot查询对象的最短引用链。

上述整个过程,基本思路如下图所示:

得到最短引用链后,LeakCanary就会弹出通知,将信息显示在界面上。
根据引用链,我们就可以比较快速的定位和分析问题。

1.3 整体流程图
上述过程整体的流程图基本上可以总结为下图,这里偷懒盗了个图:

二、使用LeakCanary
简单了解LeakCanary的原理后,我们就可以看看如何使用LeakCanary了。

2.1 导入LeakCanary对应的Jar包
在使用LeakCanary前,首先需要导入对应的Jar包。

以Android Studio为例,我们可以直接open module settings,
然后在Dependencies中搜索并增加leakCanary所需的库。

正常情况下,我们需要同时引入release和debug版本的库,
然后通过配置build.gradle,使得leakCanary仅在debug版本工作。
例如,在build.gradle中增加以下信息:

dependencies {    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.x'    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.x'}

2.2 监控Activity是否泄露
导入LeakCanary后,监控Activity是否泄露的操作极其简单。

我们只需要重写Application类的onCreate方法即可,如下所示:

public class App extends Application {    @Override    public void onCreate() {        super.onCreate();        //仅需这步操作即可        //返回一个预定义的 RefWatcher        //同时也会启用一个ActivityRefWatcher,自动监控调用Activity.onDestroy()之后泄露的activity        LeakCanary.install(this);        ..................    }}

如果检测到某个 activity 有内存泄露 ,LeakCanary 就是自动地显示一个通知。

2.3 监控其它对象是否泄露
2.2中提到的方法,主要用于检测应用中的Activity是否泄露。
如果需要监控应用中的其它对象是否泄露,则需要主动观察该对象。
当然,这部分工作也及其容易。

我们以监控Fragment为例,看看对应的操作:

public class App extends Application {    //Application为整个应用保存全局的RefWatcher    private RefWatcher refWatcher;    @Override    public void onCreate() {        super.onCreate();        refWatcher = LeakCanary.install(this);    }    public static RefWatcher getRefWatcher(Context context) {        App application = (App) context.getApplicationContext();        return application.refWatcher;    }}

之后就可以使用 RefWatcher监控 Fragment了,例如:

public abstract class BaseFragment extends Fragment {    @Override    public void onDestroy() {        super.onDestroy();        RefWatcher refWatcher = App.getRefWatcher(getActivity());        refWatcher.watch(this);    }}