LeakCanary是Square开源的,用于检测活动的内存泄漏。
众所周知LeakCanary的使用时在application中调用LeakCanary.install(this)即可。但是LeakCanary究竟是如何分析内存泄漏并且产生通知的呢?
从LeakCanary的入口开始分析:(不要扣代码,只需了解大致实现思路即可)
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.installOnIcsPlus((Application)this.context, refWatcher);
}
return refWatcher;
}
获取RefWatcher的实例,并调用ActivityRefWatcher的installOnIcsPlus方法。RefWatcher从名字看就是检测引用的。
public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
if(VERSION.SDK_INT >= 14) {
ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
activityRefWatcher.watchActivities();
}
}
从这里可以看出,LeakCanary的使用是有sdk版本要求的。调用ActivityRefWatcher 的watchActivities方法。
public void watchActivities() {
this.stopWatchingActivities();
this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
}
注册了application的生命周期的回调,用于监听activity的生命周期的回调。再看一下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);
}
};
void onActivityDestroyed(Activity activity) {
this.refWatcher.watch(activity);
}
发现只对onDestroy进行了监听。
public void watch(Object watchedReference) {
this.watch(watchedReference, "");
}
public void watch(Object watchedReference, String referenceName) {
if(this != DISABLED) {
Preconditions.checkNotNull(watchedReference, "watchedReference");
Preconditions.checkNotNull(referenceName, "referenceName");
long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
this.retainedKeys.add(key);
KeyedWeakReference reference = new KeyedWeakReference(watchedReference, key, referenceName, this.queue);
this.ensureGoneAsync(watchStartNanoTime, reference);
}
}
在activity调用onDestroy的时候,将该activity的引用进行watch。 this.retainedKeys.add(key);retainedKeys是一个Set集合。在一个活动传给RefWatcher时会创建一个唯一的对应这个活动,该密钥存入一个集合retainedKeys中。也就是说,所有我们想要观测的activity对应的retainedKeys唯一键都会被放入集合中。(如果为null,表示回收了;如果不为null,表示该activity出现了内存泄漏)然后调用ensureGoneAsync。
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;
}
}
private void removeWeaklyReachableReferences() {
KeyedWeakReference ref;
while((ref = (KeyedWeakReference)this.queue.poll()) != null) {
this.retainedKeys.remove(ref.key);
}
}
在调用onDestroy时,会将activity放入ReferenceQueue中;经removeWeaklyReachableReferences方法会将gc后依旧不为null的引用从retainedKeys中remove掉(此时retainedKeys中全是经过gc后为null的)。最后将ReferenceQueue中的value值对应retainedKeys找出不为null的value,这些即为内存泄漏的引用。
利用HeapAnalyzer对dump的内存情况进行分析并进一步确认,若确定发生泄漏,则利用DisplayLeakService发送通知。