LeakCanary:检测Android中的内存泄漏

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, 并以通知的形式展示出来。

图形路程图如下所示:

LeakCanary:检测Android中的内存泄漏_第1张图片

参考致谢:

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

2 LeakCanary Github介绍

3 LeakCanary开源项目

你可能感兴趣的:(android,内存,内存泄露,leakcanary)