LeakCanary原理浅析
1.LeakCanary简介
LeakCanary是一个Android和Java的内存泄漏检测库,可以大幅可以大幅度减少了开发中遇到的OOM问题。
LeakCanary开源库的地址为:LeakCanary开源库
LeakCanary的README地址如下:LeakCanary的README
2.如何使用LeakCanary
使用LeakCanary非常简单,只需要在Application的onCreate()方法里面调用LeakCanary.install(this)方法,就像下面一样:
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 如果是在HeapAnalyzer进程里,则返回,因为该进程是专门用来堆内存分析的。
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()的方法来进行必要的初始化工作,来监听内存泄漏。
LeakCanary.install(this);
// Normal app init code...
}
}
如果只想检测Activity的内存泄漏,而且只想使用默认的报告方式,则只需按照上面的实例,在Application里面添加一行代码:
LeakCanary.install(this);
如果想监控Fragment等其他有生命周期函数的方法的类是否有内存泄漏时,可以先返回一个RefWatcher对象,然后通过RefWatcher监控那些本该被回收的对象。使用示例如下:
public class ExampleApplication extends Application {
public static RefWatcher getRefWatcher(Context context) {
ExampleApplication application = (ExampleApplication) context.getApplicationContext();
return application.refWatcher;
}
private RefWatcher refWatcher;
@Override public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);
}
}
使用RefWatcher监控Fragment:
public abstract class BaseFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
可以看到,不管哪种方式,都需要调用LeakCanary.install()方法,因此接下来的源码分析将从这个方法开始。
3.LeakCanary源码分析
第一部分:初始化工作
先来看下LeakCanary初始化工作时序图:
接下来将从LeakCanary的install()方法开始分析LeakCanary的工作流程。
3.1 LeakCanary.install()
/*
* 创建一个RefWatcher,用来监控Activity的引用
*/
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();//见3.2,3.3,3.4
}
refWatcher(application)方法返回的是一个AndroidRefWatcherBuilder,通过这个Builder来配置RefWatcher的一些设置参数。
public static AndroidRefWatcherBuilder refWatcher(Context context) {
return new AndroidRefWatcherBuilder(context);
}
3.2 AndroidRefWatcherBuilder.listenerServiceClass()
/*
* 设置一个自定义的AbstractAnalysisResultService服务来监听内存分析结果
*/
public AndroidRefWatcherBuilder listenerServiceClass(
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}
通过ServiceHeapDumpListener类来保存listenerServiceClass服务,然后再通过RefWatcherBuilder来保存HeapDump的listener。
public ServiceHeapDumpListener(Context context,
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
setEnabled(context, listenerServiceClass, true);
setEnabled(context, HeapAnalyzerService.class, true);
this.listenerServiceClass = checkNotNull(listenerServiceClass, "listenerServiceClass");//保存listenerServiceClass
this.context = checkNotNull(context, "context").getApplicationContext();
}
public final T heapDumpListener(HeapDump.Listener heapDumpListener) {
this.heapDumpListener = heapDumpListener;//保存HeapDump的listener
return self();
}
可以看到,listenerServiceClass()方法主要保存监听内存分析结果的listener,当内存分析结果完成后,则回调该listener,在这里这个listener是DisplayLeakService服务。
3.3 RefWatcherBuilder.excludedRefs()
/*
* 该方法主要是排除一些开发可以忽略的泄漏路径(一般是系统级别BUG),这些枚举在AndroidExcludedRefs这个类当中定义
*/
public final T excludedRefs(ExcludedRefs excludedRefs) {
this.excludedRefs = excludedRefs;
return self();
}
由于AndroidRefWatcherBuilder继承自RefWatcherBuilder,excludedRefs()方法只在RefWatcherBuilder类中定义,因此调用的是RefWatcherBuilder.excludedRefs()方法,该方法的主要作用是告诉需要忽略哪些已知的系统泄漏Bug,避免这些结果产生干扰。
3.4 AndroidRefWatcherBuilder.buildAndInstall()
/*
* 创建一个RefWatcher实例,并且开始监控Activity实例引用
*/
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = build();//构建一个RefWatcher,见3.5
// 如果RefWatcher可用,则让泄漏通知显示服务生效,并且注册监听。
if (refWatcher != DISABLED) {
LeakCanary.enableDisplayLeakActivity(context);
ActivityRefWatcher.install((Application) context, refWatcher);//注册监听,见3.6
}
return refWatcher;
}
该方法的主要作用是构建一个RefWatcher类,并判断RefWatcher是否可用,如果可用的话,则让泄漏通知显示服务生效,并且注册监听。
3.5 RefWatcherBuilder.build()
/*
* 构建一个RefWatcher对象
*/
public final RefWatcher build() {
//如果禁用了,则返回
if (isDisabled()) {
return RefWatcher.DISABLED;
}
// 保留被排出系统的泄漏Bug
ExcludedRefs excludedRefs = this.excludedRefs;
if (excludedRefs == null) {
excludedRefs = defaultExcludedRefs();
}
// 保存HeapDump的listener,监听内存分析结果
HeapDump.Listener heapDumpListener = this.heapDumpListener;
if (heapDumpListener == null) {
heapDumpListener = defaultHeapDumpListener();
}
// 保存调试控制,如果是处理调试阶段,则忽略内存泄漏监控
DebuggerControl debuggerControl = this.debuggerControl;
if (debuggerControl == null) {
debuggerControl = defaultDebuggerControl();
}
// 保存HeapDumper,如果没有定义,则使用默认的HeapDumper,为AndroidHeapDumper。
HeapDumper heapDumper = this.heapDumper;
if (heapDumper == null) {
heapDumper = defaultHeapDumper();
}
// 保存WatchExecutor,如果没有定义,则使用默认的WatchExecutor,为AndroidWatchExecutor。
WatchExecutor watchExecutor = this.watchExecutor;
if (watchExecutor == null) {
watchExecutor = defaultWatchExecutor();
}
// 保存GcTrigger,如果没有定义,则使用默认的GcTrigger,为GcTrigger.DEFAULT
GcTrigger gcTrigger = this.gcTrigger;
if (gcTrigger == null) {
gcTrigger = defaultGcTrigger();
}
return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
excludedRefs);//调用RefWatcher的构造方法,保留设置的参数
}
RefWatcher(WatchExecutor watchExecutor, DebuggerControl debuggerControl, GcTrigger gcTrigger,
HeapDumper heapDumper, HeapDump.Listener heapdumpListener, ExcludedRefs excludedRefs) {
this.watchExecutor = checkNotNull(watchExecutor, "watchExecutor");
this.debuggerControl = checkNotNull(debuggerControl, "debuggerControl");
this.gcTrigger = checkNotNull(gcTrigger, "gcTrigger");
this.heapDumper = checkNotNull(heapDumper, "heapDumper");
this.heapdumpListener = checkNotNull(heapdumpListener, "heapdumpListener");
this.excludedRefs = checkNotNull(excludedRefs, "excludedRefs");
retainedKeys = new CopyOnWriteArraySet<>();//保存key的集合
queue = new ReferenceQueue<>();//引用队列
}
可以看到build()方法主要是根据之前设置的一些参数来构建RefWatcher对象,如果有参数没有初始化,则使用默认的配置参数来初始化。在RefWatcher中,还有两个比较关键的成员,分别是retainedKeys和queue,他们在后面判断一个对象是否泄漏将会被用到。
3.6 ActivityRefWatcher.install()
/*
* 注册监听
*/
public static void install(Application application, RefWatcher refWatcher) {
new ActivityRefWatcher(application, refWatcher).watchActivities();//见3.7
}
该方法首先是创建一个ActivityRefWatcher对象,该对象用来确保Activity被销毁的时候不会泄漏。接着调用watchActivities()来监控Activity实例是否泄漏了。
public ActivityRefWatcher(Application application, RefWatcher refWatcher) {
this.application = checkNotNull(application, "application");
this.refWatcher = checkNotNull(refWatcher, "refWatcher");
}
3.7 ActivityRefWatcher.watchActivities()
public void watchActivities() {
// Make sure you don't get installed twice.
stopWatchingActivities();//避免两次重复注册
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);//调用Application的registerActivityLifecycleCallbacks()方法,该方法只在Android 4.0以后才支持,见3.8
}
watchActi