Android开发中经常会出现OOM的情况,使用LeakCanary可以对于OOM进行检测与分析,那么这一篇就通过分析LeakCanary
的源码来看看是如何检测内存泄露的。
LeakCanary使用
gradle中添加依赖,如下
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
然后在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);
}
通过这样就实现了LeakCanary使用。
LeakCanary源码分析
上面使用的关键代码就是LeakCanary.install(this),来看看这里的源码
public static RefWatcher install(Application application) {
return ((AndroidRefWatcherBuilder)refWatcher(application).listenerServiceClass(DisplayLeakService.class).excludedRefs(AndroidExcludedRefs.createAppDefaults().build())).buildAndInstall();
}
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = this.build();
if(refWatcher != RefWatcher.DISABLED) {
LeakCanary.enableDisplayLeakActivity(this.context);
ActivityRefWatcher.install((Application)this.context, refWatcher);
}
return refWatcher;
}
这里其实是调用了AndroidRefWatcherBuilder类中的buildAndInstall方法,这里首先是生成了一个RefWatcher,接下来把这个对象与提供的pplication传入到
ActivityRefWatcher.install方法,我们去看这个方法,如下
public static void install(Application application, RefWatcher refWatcher) {
(new ActivityRefWatcher(application, refWatcher)).watchActivities();
}
public void watchActivities() {
this.stopWatchingActivities();
this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
}
这里主要调用了watchActivities方法,而这个方法里面则是向application里注册了一个ActivitylifecycleCallbacks的回调函数,可以用来监听Application整个生命周期所有Activity的lifecycle事件
接下来我们看一下LeakCanary中提供的这个lifecycleCallbacks,如下
private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
public void onActivityStarted(Activity activity) {
}
public void onActivityResumed(Activity activity) {
}
public void onActivityPaused(Activity activity) {
}
public void onActivityStopped(Activity activity) {
}
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
public void onActivityDestroyed(Activity activity) {
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
};
可以看到这里只是监听了所有Activity的onActivityDestroyed事件,当Activity被Destory时,调用ActivityRefWatcher.this.onActivityDestroyed(activity)函数。
接下来看一下这个ActivityRefWatcher中的onActivityDestroyed方法到底做了什么事情,源码如下
void onActivityDestroyed(Activity activity) {
this.refWatcher.watch(activity);
}
这里调用了RefWatcher的watch方法,通过调用后,如下
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
this.watchExecutor.execute(new Retryable() {
public Result run() {
return RefWatcher.this.ensureGone(reference, watchStartNanoTime);
}
});
}
Result ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = TimeUnit.NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
this.removeWeaklyReachableReferences();
if(this.debuggerControl.isDebuggerAttached()) {
return Result.RETRY;
} else if(this.gone(reference)) {
return Result.DONE;
} else {
this.gcTrigger.runGc();
this.removeWeaklyReachableReferences();
if(!this.gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = TimeUnit.NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
File heapDumpFile = this.heapDumper.dumpHeap();
if(heapDumpFile == HeapDumper.RETRY_LATER) {
return Result.RETRY;
}
long heapDumpDurationMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
this.heapdumpListener.analyze(new HeapDump(heapDumpFile, reference.key, reference.name, this.excludedRefs, watchDurationMs, gcDurationMs, heapDumpDurationMs));
}
return Result.DONE;
}
}
我们主要看一下ensureGone中的内容
在一个 activity 传给 RefWatcher 时会创建一个唯一的key对应这个activity,该key存入一个集合retainedKeys中。也就是说,所有我们想要观测的activity对应的唯一key都会被放入retainedKeys集合中。
基于我们对ReferenceQueue的了解,只要把队列中所有的reference取出来,并把对应retainedKeys里的key移除,剩下的key对应的对象都没有被回收。
1.ensureGone 首先调用removeWeaklyReachableReferences把已被回收的对象的key从retainedKeys移除,剩下的key都是未被回收的对象;
2.if(gone(reference))用来判断某个reference的key是否仍在retainedKeys里,若不在,表示已回收,否则继续;
3.gcTrigger.runGc();手动出发GC立即把所有WeakReference引用的对象回收;
4.removeWeaklyReachableReferences();再次清理retainedKeys,如果该reference还在retainedKeys里(if(!gone(reference))),表示泄漏;
5.利用heapDumper把内存情况dump成文件,并调用heapdumpListener进行内存分析,进一步确认是否发生内存泄漏。
6.如果确认发生内存泄漏,调用DisplayLeakService发送通知。
到这里leakCanary对于内存泄露的检测分析流程就完成了。
关于ActivityLifecycleCallbacks
ActivityLifecycleCallbacks是Application中声明的一个内部接口,结构如下
public interface ActivityLifecycleCallbacks {
void onActivityCreated(Activity activity, Bundle savedInstanceState);
void onActivityStarted(Activity activity);
void onActivityResumed(Activity activity);
void onActivityPaused(Activity activity);
void onActivityStopped(Activity activity);
void onActivitySaveInstanceState(Activity activity, Bundle outState);
void onActivityDestroyed(Activity activity);
}
Application提供有一个registerActivityLifecycleCallbacks()的方法,需要传入的参数就是这个ActivityLifecycleCallbacks接口,作用和你猜的没错,就是在你调用这个方法传入这个接口实现类后,系统会在每个Activity执行完对应的生命周期后都调用这个实现类中对应的方法。
另外registerActivityLifecycleCallbacks()内部是把ActivityLifecycleCallbacks加到一个集合中,所以ActivityLifecycleCallbacks可以添加多个
而且ActivityLifecycleCallbacks只是在项目初始化的时候被装到集合中,并不会初始化任何东西,直到真正Activity执行到相应的生命周期,才会执行ActivityLifecycleCallbacks中的操作
所有使用ActivityLifecycleCallbacks会使我们代码会更加有创造力,因为使用ActivityLifecycleCallbacks可以实现很多不同的功能,而且是优雅的实现
简单想了一下ActivityLifecycleCallbacks可以实现什么功能。
- 关于BaseActiviy的封装
- 关于一些通用需要注册绑定以及解绑和解注册的操作
- 关于前后台状态的检测
等等。。。
网友评论