LeakCanary:检测Android中的内存泄漏

来源:互联网 发布:国外人工智能奖项 编辑:程序博客网 时间:2024/05/23 19:58

Square开源了一个内存泄露自动探测神器——LeakCanary,它是一个Android和Java的内存泄露检测库,可以大幅度减少了开发中遇到的OOM问题,对于开发者来说,无疑是个福音,下面对该库的使用进行简单的介绍。

一 什么是内存泄漏:

有些对象只有有限的生命周期。当它们的任务完成之后,它们将被垃圾回收。如果在对象的生命周期本该结束的时候,这个对象还被一系列的引用,这就会导致内存泄漏。随着泄漏的累积,app将消耗完内存。

比如,在Activity.onDestroy()被调用之后,view树以及相关的bitmap都应该被垃圾回收。如果一个正在运行的后台线程继续持有这个Activity的引用,那么相关的内存将不会被回收,这最终将导致OutOfMemoryError崩溃。

二 LeakCanary介绍:

一个用于检测Android&Java的内存泄漏检测库

A memory leak detection library for Android and Java.

“A small leak will sink a great ship.” - Benjamin Franklin
小漏不补沉大船。——本杰明 富兰克林

三 DEMO使用:

(1)在build.gradle中添加依赖:

dependencies {   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2'   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2'   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' }

(2)在Application中初始化Leak:

public class MyApp extends Application {    private static MyApp instance;    @Override    public void onCreate() {        super.onCreate();        instance = this;        LeakCanary.install(this);//初始化LeakCanary    }    public static final MyApp getInstance() {        return instance;    }    @Override    public void onTerminate() {        super.onTerminate();    }}

或者这样初始化:

public class MyApplication extends Application {//在自己的Application中添加如下代码  public static RefWatcher getRefWatcher(Context context) {    ExampleApplication application = (MyApplication) context.getApplicationContext();    return application.refWatcher;  }  private RefWatcher refWatcher;  @Override public void onCreate() {    super.onCreate();    refWatcher = LeakCanary.install(this);  }}

(3)在Activity中制造一个内存泄漏的场景:

MainActivity.java:

public class MainActivity extends AppCompatActivity {    public static MainActivity instance = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        instance = this;//创建一个静态对象instance,保持其对当前activity的引用;        findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                Intent intent = new Intent();                intent.setClass(MainActivity.this, SecondActivity.class);                MainActivity.this.startActivity(intent);            }        });    }    @Override    protected void onDestroy() {        super.onDestroy();        //instance=null;   //当要销毁activity的时候,instance并未置空,仍然保持对MainActivity的引用,因此MainActivity不会销毁;    }}

SecondActivity.java:

public class SecondActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                MainActivity.instance.finish();//通过instance关闭MainActivity;            }        });    }}

在finish的时候会出现内存泄漏,instance仍然保持对activity的引用。

(4)运行结果如下:

这里写图片描述

然后点击桌面的Leaks图标可以看到:

这里写图片描述

Leaks指出了内存泄漏的位置是instance。

(5)LeakCanary的检测工作机制:

LeakCanary检测内存泄漏的原理大概分为7个步骤,从创建被关联对象的弱引用、检查该应用是否被清除等。

1、创建:RefWatcher.watch() 创建一个 KeyedWeakReference 到要被监控的对象。2、检查:然后在后台线程检查引用是否被清除,如果没有,调用GC。3、存放:如果引用还是未被清除,把 heap 内存 dump 到 APP 对应的文件系统中的一个 .hprof 文件中。4、解析:在另外一个进程中的 HeapAnalyzerService 有一个 HeapAnalyzer 使用HAHA 解析这个文件。5、定位:得益于唯一的 reference key, HeapAnalyzer 找到 KeyedWeakReference,定位内存泄露。6、计算:HeapAnalyzer 计算 到 GC roots 的最短强引用路径,并确定是否是泄露。如果是的话,建立导致泄露的引用链。7、展示:引用链传递到 APP 进程中的 DisplayLeakService, 并以通知的形式展示出来。

图形路程图如下所示:

这里写图片描述

参考致谢:

1 利用 LeakCanary 来检查 Android 内存泄漏

2 LeakCanary Github介绍

3 LeakCanary开源项目

0 0
原创粉丝点击