LeakCanary

  是Square公司基于MAT(Memory Analyzer Tool内存分析工具),开源的一个能够简单迅速的发现内存泄漏的第三方库。是一个为了Android使用的内存检测分析工具。

  LeakCanary的原理如下:正常情况下一个Activity在执行Destroy之后就会被销毁,LeakCanary做的就是在一个Activity被Destroy之后将它放在一个WeakReference中,然后将这个WeakReference关联到一个ReferenceQueue,查看ReferenceQueue队列中是否存在这个Activity的引用,如果不在这个队列中,执行一些GC清洗操作,再次查看。如果仍然不存在,则证明该Activity泄漏了,之后Dump出heap信息,并去分析泄漏路径。

  出现简单的内存泄漏可以方便地通过打开Leaks内存泄漏文件,快速定位内存泄漏的位置,对于复杂的内存泄漏问题可以通过查看LeakCanary库生成的hprof文件进行分析。

  在app的build.gradle文件中引入leakcanary-android依赖:

dependencies{
    //引入LeakCanary库;
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
}

LeakCanary的使用

  在2.0版本之前的,接入LeakCanary的的时候,除了在build.gradle中引入项目外,还需要在自定义的Application中调用LeakCanary.install(this)来进行初始化工作。在2.0之后的版本,只需要在build.gradle引入项目就可以了。

2.0版本之前使用

  在自定义的Application类的onCreate()方法中,添加一下代码进行初始化。

@Override
public void onCreate() {
    super.onCreate();
    //初始化LeakCanary;
    if (LeakCanary.isInAnalyzerProcess(this)) {
        return;
    }
    LeakCanary.install(this);
}

  如果当前的进程是用来给LeakCanary 进行堆分析的则return,否则会执行LeakCanary的install方法。这样我们就可以使用LeakCanary了,如果检测到某个Activity 有内存泄露,LeakCanary 就会给出提示。
但是目前的代码只能够检测Activity的内存泄漏,当然还存在其他类的内存泄漏,这时我们就需要使用RefWatcher来进行监控。

public class AppApplication extends Application {

    private RefWatcher refWatcher;
    
    @Override
    public void onCreate() {
        super.onCreate();
        refWatcher= setupLeakCanary();
    }

    private RefWatcher setupLeakCanary() {
        if (LeakCanary.isInAnalyzerProcess(this)) {
            return RefWatcher.DISABLED;
        }
        return LeakCanary.install(this);
    }

    public static RefWatcher getRefWatcher(Context context) {
        AppApplication leakApplication = (AppApplication) context.getApplicationContext();
        return leakApplication.refWatcher;
    }
}

使用小结:

如果只关注activity的内存泄漏,那么在Application中onCreate加入第一部分的代码就OK了;如果还关注fragment的泄漏情况,那么Application加上第二部分的代码,然后在对应fragment页面中onDestroy中加入以下代码:

RefWatcher refWatcher = MyApplication.getRefWatcher(this);
     refWatcher.watch(this);

原理介绍

  • 触发检测: 每次当Activity/Fragment执行完onDestroy生命周期,LeakCanary就会获取到这个Activity/Fragment,然后初始化RefWatcher对它进行分析,查看是否存在内存泄漏。
  • 判断是否存在内存泄漏: 首先尝试着从ReferenceQueue队列中获取待分析对象(软引用和弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用或弱引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用或弱引用加入到与之关联的引用队列中),如果不为空,那么说明正在被系统回收,如果直接就返回DONE,说明已经被系统回收了,如果没有被系统回收,可能存在内存泄漏,手动触发系统GC,然后再尝试移除待分析对象,如果还存在,说明存在内存泄漏。
  • 分析内存泄漏: 确定有内存泄漏后,调用heapDumper.dumpHeap()生成.hprof文件目录。HAHA 是一个由 square 开源的 Android 堆分析库,分析 hprof 文件生成Snapshot对象。Snapshot用以查询对象的最短引用链。找到最短引用链后,定位问题,排查代码将会事半功倍。

2.0版本以后的用法

  检测Activity内存泄漏原理图如下:

1 . 注册监听Activity生命周期onDestroy事件;
2 . 在Activity onDestroy事件回调中创建KeyedWeakReference对象(继承自WeakReference),并关联ReferenceQueue;
3 . 延时5秒检查目标对象是否回收;
4 . 未回收则开启服务,dump heap获取内存快照hprof文件;
5 . 解析hprof文件,根据KeyedWeakReference类型过滤找到内存泄漏对象;
6 . 计算对象到GC roots的最短路径,并合并所有最短路径为一棵树;
7 . 输出分析结果,并根据分析结果展示到可视化页面;

注意事项

以下问题导致有内存泄漏发生时LeakCanary不发生通知:
1.你的应用需要有写SD权限,因为LeakCanary需要生成hprof文件,保存在SD卡里面,因此你的应用要先申请权限

<!– SDCard中创建与删除文件权限 –>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!– 向SDCard写入数据权限 –>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

-
-
-
-
-
-
-
-
-
-
-
-
-
------------------last line for now-----------------