LeakCanary
Posted wytiger
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeakCanary相关的知识,希望对你有一定的参考价值。
一、简介
使用MAT来分析内存问题,有一些门槛,会有一些难度,并且效率也不是很高,对于一个内存泄漏问题,可能要进行多次排查和对比才能找到问题原因。 为了能够简单迅速的发现内存泄漏,Square公司基于MAT开源了LeakCanary
二、使用
在app build.gradle 中加入引用:
dependencies {
debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.5‘
releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.5‘
testCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.5‘
}
在 Application 中:
public class LeakApplication extends Application {
@Override public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {//1
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
}
}
如果当前的进程是用来给LeakCanary 进行堆分析的则return,否则会执行LeakCanary的install方法。这样我们就可以使用LeakCanary了,如果检测到某个Activity 有内存泄露,LeakCanary 就会给出提示。
例子代码只能够检测Activity的内存泄漏,当然还存在其他类的内存泄漏,这时我们就需要使用RefWatcher来进行监控。改写Application,如下所示:
public class MyApplication 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) {
MyApplication leakApplication = (MyApplication) context.getApplicationContext();
return leakApplication.refWatcher;
}
}
install方法会返回RefWatcher用来监控对象,LeakApplication中还要提供getRefWatcher静态方法来返回全局RefWatcher。
最后为了举例,我们在一段存在内存泄漏的代码中引入LeakCanary监控,如下所示。
public class OtherActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeakThread leakThread = new LeakThread();
leakThread.start();
}
class LeakThread extends Thread {
@Override
public void run() {
try {
CommonUtils.getInstance(OtherActivity.this);
Thread.sleep(6 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = MyApplication.getRefWatcher(this);//1
refWatcher.watch(this);
}
}
MainActivity存在内存泄漏,原因就是非静态内部类LeakThread持有外部类MainActivity的引用,LeakThread中做了耗时操作,导致MainActivity无法被释放。
它用于自动监控Activity执行onDestroy方法之后是否发生内存泄露,当前此例onDestroy加是多余的,这里只是为了方便举例,如果想要监控Fragment,在Fragment中添加如上的onDestroy方法是有用的。
运行程序,这时会在界面生成一个名为Leaks的应用图标。接下来不断的切换横竖屏,这时会闪出一个提示框,提示内容为:“Dumping memory app will freeze.Brrrr.”。再稍等片刻,内存泄漏信息就会通过Notification展示出来。
提示的notification:
使用小结:
如果只关注activity的内存泄漏,那么在Application中onCreate加入LeakCanary.install(this);就OK了,
如果还关注fragment的泄漏情况,那么Application加上RefWatcher,然后在对应fragment页面中onDestroy中加入:
RefWatcher refWatcher = MyApplication.getRefWatcher(this);
refWatcher.watch(this);
三、使用踩坑
在刚开始使用LeakCanary的时候,遇到了几个问题导致有内存泄漏发生时LeakCanary不发生通知,这里和大家分享一下。
1、 你的应用需要有写SD权限,因为LeakCanary需要生成hprof文件,保存在SD卡里面,因此你的应用要先申请权限
四、原理介绍
4.1 触发检测
每次当Activity/Fragment执行完onDestroy生命周期,LeakCanary就会获取到这个Activity/Fragment,然后初始化RefWatcher对它进行分析,查看是否存在内存泄漏。
4.2 判断是否存在内存泄漏
首先尝试着从ReferenceQueue引用队列中获取待分析对象(软引用和弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用或弱引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用或弱引用加入到与之关联的引用队列中)。如果不为空,那么说明正在被系统回收;如果直接就返回DONE,说明已经被系统回收了;如果没有被系统回收,可能存在内存泄漏,手动触发系统GC,然后再尝试移除待分析对象,如果还存在,说明存在内存泄漏。
4.3 分析内存泄漏
确定有内存泄漏后,调用heapDumper.dumpHeap()生成.hprof文件目录。HAHA 是一个由 square 开源的 Android 堆分析库,分析 hprof 文件生成Snapshot对象。Snapshot用以查询对象的最短引用链。找到最短引用链后,定位问题,排查代码将会事半功倍。
整体流程如下:
详细原理分析可以参考:LeakCanary原理分析
附:
LeakCanary 内存泄漏原理完全解析
LeakCanary,30分钟从入门到精通
以上是关于LeakCanary的主要内容,如果未能解决你的问题,请参考以下文章
工作中遇到的Android内存优化问题-leakcanary源码解析