LeakCanary 教程

LeakCanary

项目地址https://github.com/square/leakcanary

使用方法

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'

}

 

//no-op 是一个空壳,为了方便编译正式版本,这样不用改代码生成的正式版本上也不会影响性能。

 

 

代码注入:

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    if (LeakCanary.isInAnalyzerProcess(this)) {
      // This process is dedicated to LeakCanary for heap analysis.
      // You should not init your app in this process.
      return;
    }
    LeakCanary.install(this);
    // Normal app init code...
  }
}

 

LeakCanary.install 会返回一个 RefWatcher 利用 RefWatcher可以监视任意你怀疑的对象。 LeakCanary 会自动监视Activity对象。当Activity onDestory之后,LeakCanary会分析Activity的对象是否销毁。如果被销毁,那么就产生Activity对象泄露。

 泄漏反馈:

LeakCanary 自带了一个界面来显示内存泄漏的对象列表,和对象被应用的情况,如下:我手机有个系统bug,为了截屏方便持有了Activity,导致Activity消失之后没有及时被回收。   原理:

LeakCanary原理是利用Java 弱引用(WeakReference)机制监察这个弱应用持有的对象是否为null来判断对象是否被GC。 如果发现对象有泄露就调用DumpHeap来查找泄露对象的引用情况,类似MAT。

 

使用说明:

对于任何Java对象来说,程序并不确定对象是否该被释放,所以才会有内存泄漏。LeakCanary也无法判断对象是否该被释放了,它只是利用了某些对象带生命周期,正常情况对象在生命周期结束之后就该释放了。所以LeakCanary 默认只检测带Activity的对象,因为只有Activity对象的生命周期能自动监测到。而其他的对象我们可以在确定某个对象会被释放时手动调用RefWatcher的watch来手动监测。

 

 

高级功能:

  1. 设置保存的Leak Trace

默认是保存7个,可以自定义数量。

RefWatcher refWatcher = LeakCanary.refWatcher(this)
      .maxStoredHeapDumps(42)
      .buildAndInstall();
  1. 上传到服务器
public class LeakUploadService extends DisplayLeakService {
  @Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
    if (!result.leakFound || result.excludedLeak) {
      return;
    }
    myServer.uploadLeakBlocking(heapDump.heapDumpFile, leakInfo);
  }
}

public class DebugExampleApplication extends ExampleApplication {
  @Override protected RefWatcher installLeakCanary() {
    RefWatcher refWatcher = LeakCanary.refWatcher(this)
      .listenerServiceClass(LeakUploadService.class);
      .buildAndInstall();
    return refWatcher;
  }
}

<?xml version="1.0" encoding="utf-8"?>
        <manifest
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools">
    <application android:name="com.example.DebugExampleApplication">
        <service android:name="com.example.LeakUploadService" />
    </application>
</manifest>
  1. 忽略特别对象
public class DebugExampleApplication extends ExampleApplication {
  @Override protected RefWatcher installLeakCanary() {
    ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults()
        .instanceField("com.example.ExampleClass", "exampleField")
        .build();
    RefWatcher refWatcher = LeakCanary.refWatcher(this)
      .excludedRefs(excludedRefs)
      .buildAndInstall();
    return refWatcher;
  }
}
  1. 忽略某个Activity
public class DebugExampleApplication extends ExampleApplication {
  @Override protected RefWatcher installLeakCanary() {
    LeakCanary.enableDisplayLeakActivity(this);
    RefWatcher refWatcher = LeakCanary.refWatcher(this)
      // Notice we call build() instead of buildAndInstall()
      .build();
    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
      public void onActivityDestroyed(Activity activity) {
        if (activity instanceof ThirdPartyActivity) {
            return;
        }
        refWatcher.watch(activity);
      }
      // ...
    });
    return refWatcher;
  }
}

 

 

Android常规的内存泄漏

  1. Context泄漏

AndroidContext使用非常普遍,跟系统打交道的地方大多数情况需要Context。我们需要注意在Activity里调用需要Context的时候尽量不要直接传入Activity进去,避免调用的方法持有你的Activity导致Activity泄漏。再我们编写的方法需要Context的时候,也要尽量不要持有穿过类的Context对象,而是获取ApplicaionContext,从而避免了传过来的是一个Activity

  1. Static Activities,Static Views,Static big Objeces…

由于静态变量不会被任何对象持有,也就无法自动被释放。需要手动释放,所有尽量避免出现静态的Activity View ….

  1. 内部类和匿名类

内部类和匿名类都持有外部类的对象,所以再使用匿名类和内部类的时候避免持有外部实例,如果内部类和匿名类本身的生命周期无法和外部类保持一直(外部类销毁时内部类可能不会或者不会被销毁)时最好才用静态类部类

  1. 注册某些系统Listener

千万别忘了取消注册

 

打赏

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注