使用LeakCanary 只需要在Application中调用:
LeakCanary.install(this);
那么就从这里作为入口,进去看个究竟。
/**
* Creates a {@link RefWatcher} that works out of the box, and starts watching activity
* references (on ICS+).
*/
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
refWatcher()将application 传进去返回AndroidRefWatcherBuilder,listenerServiceClass是设置泄漏发送显示泄漏情况的通知栏的Service不用关注。excludedRefs()设置泄漏白名单,在enum AndroidExcludedRefs 已经枚举了一些系统的bug,这里AndroidExcludedRefs.createAppDefaults()会将所有预置的枚举都添加进去,我们也可以根据需要自己添加不想被报内存泄漏的对象。
public interface Builder {
BuilderWithParams instanceField(String className, String fieldName);
BuilderWithParams staticField(String className, String fieldName);
BuilderWithParams thread(String threadName);
BuilderWithParams clazz(String className);
ExcludedRefs build();
}
可以看到,可以设置白名单的可以是成员对象、静态对象、线程、某个类。
那么我们要自己添加白名单的话,就可以把Application中LeakCanary.install(this)方法改为:
private void initLeakCanary(){
ExcludedRefs.Builder appDefaults = AndroidExcludedRefs.createAppDefaults();
//比如添加自定义线程到白名单,其他的类似
appDefaults.thread("test thread");
RefWatcher refWatcher = LeakCanary.refWatcher(getApplication()).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(appDefaults.build())
.buildAndInstall();
}
回到前面,继续看buildAndInstall():
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
LeakCanary.enableDisplayLeakActivity(context);
ActivityRefWatcher.installOnIcsPlus((Application) context, refWatcher);
}
return refWatcher;
}
可以看到这里就是生成RefWatcher然后,ActivityRefWatcher.installOnIcsPlus((Application) context, refWatcher);
里面其实是application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
然后在lifecycleCallbacks的onActivityDestroyed中将activity传递给ActivityRefWatcher
@Override
public void onActivityDestroyed(Activity activity) {
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
ActivityRefWatcher#onActivityDestroyed()中就其实就是用RefWatcher监控activity
void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
那接着就看watch()是怎么监控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();
retainedKeys.add(key);
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
ensureGoneAsync(watchStartNanoTime, reference);
}
现生成以个UUID来作为这个监控对象(也就是activity)的key,添加到retainedKeys中去,这个retainedKeys是个CopyOnWriteArraySet。然后把这个监控对象还有一个队列生成一个KeyedWeakReference,这个是弱引用,当这个监控对象被回收的时候,这个对象就会被添加到这个队列里。
然后ensureGoneAsync(watchStartNanoTime, reference);
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
return ensureGone(reference, watchStartNanoTime);
}
});
}
这个watchExecutor是AndroidWatchExecutor,会把要执行的runable都post到主线程去执行,并且是在主线程handler空闲时执行,
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
postToBackgroundWithDelay(retryable, failedAttempts);
return false;
}
});
回过头来看ensureGone()方法
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
removeWeaklyReachableReferences();
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
if (gone(reference)) {
return DONE;
}
gcTrigger.runGc();
removeWeaklyReachableReferences();
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;
}
先调用了removeWeaklyReachableReferences();
private void removeWeaklyReachableReferences() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
retainedKeys.remove(ref.key);
}
}
先遍历弱引用队列,然后拿到监控对象的key,去set中匹配remove。然后调用
private boolean gone(KeyedWeakReference reference) {
return !retainedKeys.contains(reference.key);
}
我们刚才说监控对象如果被GC了会被添加到队列里来,即如果这个activity是有被回收的,那么就会被添加到队列里,然后就可以成功remove,再后面判断gone的时候,如果retainedKeys里已经没有这个activity的key了那么就是gone了,即已经被回收没有内存泄漏。
如果没有gone,那么gcTrigger.runGc();
GcTrigger DEFAULT = new GcTrigger() {
@Override public void runGc() {
// Code taken from AOSP FinalizationTest:
// https://android.googlesource.com/platform/libcore/+/master/support/src/test/java/libcore/
// java/lang/ref/FinalizationTester.java
// System.gc() does not garbage collect every time. Runtime.gc() is
// more likely to perfom a gc.
Runtime.getRuntime().gc();
enqueueReferences();
System.runFinalization();
}
private void enqueueReferences() {
// Hack. We don't have a programmatic way to wait for the reference queue daemon to move
// references to the appropriate queues.
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new AssertionError();
}
}
};
手动触发GC, 等待100毫秒后继续执行removeWeaklyReachableReferences(),就是看GC过后这个activity有没有成功被回收然后放入到queue里,如果这时候被回收了那就是没有泄露,如果还没有被回收就判定发生了内存泄漏,然后调用square的haha 库dump内存信息 去分析引用连。