首先进到LeakCanary 类里面的初始化静态方法。
public static @NonNull RefWatcher install(@NonNull Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall(); }
refWatcher(application) 形成了AndroidRefWatcherBuilder。来看看这个。
public @NonNull AndroidRefWatcherBuilder listenerServiceClass(
@NonNull Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
enableDisplayLeakActivity = DisplayLeakService.class.isAssignableFrom(listenerServiceClass);
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}
传入的是AbstractAnalysisResultService 实现类。很明显是堆复制监听使用。
excludedRefs(AndroidExcludedRefs.createAppDefaults().build()) 代表排除某些监听。这个后续会降到。最后落脚方法。
public @NonNull RefWatcher buildAndInstall() {
if (LeakCanaryInternals.installedRefWatcher != null) {
throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
}
//创建核心的RefWatch类。
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
if (enableDisplayLeakActivity) {
LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);
}
//观察Activity
if (watchActivities) {
ActivityRefWatcher.install(context, refWatcher);
}
//观察Fragment
if (watchFragments) {
FragmentRefWatcher.Helper.install(context, refWatcher);
}
}
//赋值静态同步变量。
LeakCanaryInternals.installedRefWatcher = refWatcher;
return refWatcher;
}
首先观察下如何发现Activity的内存泄露的。监听了 Application.ActivityLifecycleCallbacks。当Activity onDestroy的时候就可以开始检测内存泄露了,进入正题。
public static void install(@NonNull Context context, @NonNull RefWatcher refWatcher) {
Application application = (Application) context.getApplicationContext();
ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks);
}
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new ActivityLifecycleCallbacksAdapter() {
@Override public void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
};
watchedReference 就是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);
}
创建了KeyedWeakReference 的弱引用,这样不会导致Activity想释放而释放不掉的问题。
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
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。
@Override public void execute(@NonNull Retryable retryable) {
//主线程执行,先看主线程执行吧。
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
waitForIdle(retryable, 0);
} else {
//子线程执行。
postWaitForIdle(retryable, 0);
}
}
private void waitForIdle(final Retryable retryable, final int failedAttempts) {
// This needs to be called from the main thread.
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
postToBackgroundWithDelay(retryable, failedAttempts);
return false;
}
});
}
注意这个IdleHandler 加入到主线程的Looper。这个代表了主线程开始空闲的时候,可以开始执行
postToBackgroundWithDelay(retryable, failedAttempts); 从这里我们已经走了一部分逻辑了。
private 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() {
Retryable.Result result = retryable.run();
if (result == RETRY) {
postWaitForIdle(retryable, failedAttempts + 1);
}
}
}, delayMillis);
}
retryable.run()就是这行的
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;
}
//开始出发gc。
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);
//查询相关Activity的堆栈。
HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
.referenceName(reference.name)
.watchDurationMs(watchDurationMs)
.gcDurationMs(gcDurationMs)
.heapDumpDurationMs(heapDumpDurationMs)
.build();
//进行分析。这个过程我就不分析了。
heapdumpListener.analyze(heapDump);
}
return DONE;
}
到这里LeakCanary具备分析内存泄露的原理就说明白了,核心的如何分析堆栈找出具体的类怎么泄露的,这里放到下面一章节去分析。
分析源码有个好处就是本来是一个黑盒模型,非得去查看里面具体的构造这么一个过程,你说很烦吧,确实烦,但是搞明白了,那也确实是爽。并且分析优秀框架过程其实无形中锻炼了你自己的代码水平,所以这是一条提升必然的逻辑了。
本文详细解析了LeakCanary的内存泄漏检测机制,包括其如何通过监听Activity生命周期来发现潜在泄漏,并利用弱引用及堆分析定位具体泄漏源头。
766

被折叠的 条评论
为什么被折叠?



