LeakCanary使用总结

I. 使用

build.gradle中配置:

1
2
3
4
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
}

Application class中配置:

1
2
3
4
5
6
7
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}

II. 初始化与原理

根据build.gradle配置:

debug包走:com.squareup.leakcanary:leakcanary-android:1.3
release包走: com.squareup.leakcanary:leakcanary-android-no-op:1.3

分别解析

release

release包,LeakCanary.install(this)就是返回了一个RefWatcher#DISABLED,而RefWatcher#DISABLE中返回的都是空方法。

debug包

1
2
3
4
5
6
7
8
9
10
11
12
13
public static RefWatcher install(Application application,
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
// listenerServiceClass = DisplayLeakService.class
if (isInAnalyzerProcess(application)) {
return RefWatcher.DISABLED;
}
enableDisplayLeakActivity(application);
HeapDump.Listener heapDumpListener =
new ServiceHeapDumpListener(application, listenerServiceClass);
RefWatcher refWatcher = androidWatcher(heapDumpListener);
ActivityRefWatcher.installOnIcsPlus(application, refWatcher);
return refWatcher;
}
  1. 如果是HeapAnalyzerService的进程(非app主的进程),返回一个DISABLED。否则创建一个Android默认配置的RefWatcher
  2. 创建一个Application#ActivityLifecycleCallbacks,并且注册到当前Application上(由于该Api是在api 14才有的,因此低版本没有注册),主要是为了,在所有的Activity#onDestroy执行的最后通过调用RefWatcher#watch(Object)来检测Activity是否出现了泄漏。

RefWatcher#watch(Object o)基本原理

  1. 先促发一次GC
  2. 如果o依然存在,dump heap到本地
  3. dump完成后启动HeapAnalyzerService服务(如果不存在)(单独进程)
  4. HeapAnalyzerService中读取本地dump下来的文件,使用HAHA库进行分析。
  5. 如果检测到内存泄漏,将结果返回给DisplayLeakService服务,并且显示通知

III. 定位检测情况

推荐log关键字

1
leak | hprof | analysis

下面是几个案例

1
adb logcat | grep -e "leak" -e "hprof" -e "analysis"

IV. 注意点

  1. release千万不要带上(带no-op包),由于GC耗时,因此会带来:安装包增加、应用onDestory由于gc带来耗时、由于新建的分析进程带来内存开销,由于大量的计算分析,带来的CPU资源的占用。
  2. Android api 14以下的LeakCanary#install(Application):RefWatcher是不会自动注册对Activity的检测的,需要自己实现BaseActivity并且在Activity#onDestroy的地方主动调用RefWatcher#watch(Object)进行检测
  3. 检测是比较慢的,其中涉及i/o,涉及大量的计算分析,通常在20s~1分钟左右,根当前cpu资源占用情况有关。

Jacksgong wechat
欢迎关注Jacks Blog公众号,第一时间接收原创技术沉淀干货。