先明确一个概念 new WeakReference(object, ReferenceQueue)
参数说明 object: 任意对象 ReferenceQueue:一个队列 后边简称queue
当object被gc回收后 上边new 出来的WeakReference将会加入到其参数ReferenceQueue队列中(juejin.cn/post/695343…)
leakcanary流程:基于1.5.4
1.监听activity生命周期 LeakCanary.install
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
//监听activity生命周期
.buildAndInstall();
}
2.ondestroy后创建一个key加入set集合,再将key和activity包装到KeyedWeakReference对象中(简称ref)
@Override
public void onActivityDestroyed(Activity activity) {
//destroy回调
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
checkNotNull(watchedReference, "watchedReference");
checkNotNull(referenceName, "referenceName");
final long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
//保存key
retainedKeys.add(key);
//包装成ref
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
ensureGoneAsync(watchStartNanoTime, reference);
}
3.发送一个idle到主线程空闲时执行
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
return ensureGone(reference, watchStartNanoTime);
}
});
}
//watchExecutor的创建
public AndroidRefWatcherBuilder watchDelay(long delay, TimeUnit unit) {
return watchExecutor(new AndroidWatchExecutor(unit.toMillis(delay)));
}
void waitForIdle(final Retryable retryable, final int failedAttempts) {
//加入idle列表
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
postToBackgroundWithDelay(retryable, failedAttempts);
return false;
}
});
}
void postToBackgroundWithDelay(final Retryable retryable, final int failedAttempts) {
long exponentialBackoffFactor = (long) Math.min(Math.pow(2, failedAttempts), maxBackoffFactor);
long delayMillis = initialDelayMillis * exponentialBackoffFactor;
backgroundHandler.postDelayed(new Runnable() {
@Override public void run() {
//这里回到刚才的run执行ensureGone
Retryable.Result result = retryable.run();
if (result == RETRY) {
postWaitForIdle(retryable, failedAttempts + 1);
}
}
}, delayMillis);
}
4.遍历queue中是否有ref,找到就从set集合中删除key(说明对象已经被回收。这里注意:当object被gc回收后 创建的weakReference对象将会加入到queue队列,所以找到说明对象已经被回收,不存在泄露) 否则,调用系统gc后再重新在queue中找,如果还是没有找到说明可能泄露了,最后打印堆栈
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
//这里检测queue里有没有weakrefrence对象,有说明成功回收了并移除key
removeWeaklyReachableReferences();
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
//这里重新检查key还在不在,如果在说明上边queue里没有weakrefrence对象,也就是对象还没有被回收
if (gone(reference)) {
return DONE;
}
//调用gc
gcTrigger.runGc();
//再重新检测
removeWeaklyReachableReferences();
//key还存在说明queue里没出现weakrefrence对象(可能存在泄露)
if (!gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
//打印堆栈
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
return DONE;
}