2.源码分析
我们在build.gradle文件中加入Leakcanary依赖库:
代码语言:txt复制 debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
LeakCanary的使用从LeakCanary.install(this)开始,
下面我们从入口开始分析:
代码语言:txt复制//LeakCanary.java
代码语言:txt复制 /**
代码语言:txt复制 * Creates a {@link RefWatcher} that works out of the box, and starts watching activity
* references (on ICS ).
*/
public static @NonNull RefWatcher install(@NonNull Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
代码语言:txt复制 public static @NonNull AndroidRefWatcherBuilder refWatcher(@NonNull Context context) {
代码语言:txt复制 return new AndroidRefWatcherBuilder(context);
代码语言:txt复制 }
builder模式构建了一个RefWatcher对象,listenerServiceClass()方法绑定了一个后台服务DisplayLeakService
这个服务主要用来分析内存泄漏结果并发送通知。你可以继承并重写这个类来进行一些自定义操作,比如上传分析结果等。
我们最后看buildAndInstall()方法:
代码语言:txt复制#AndroidRefWatcherBuilder.java
代码语言:txt复制 /**
代码语言:txt复制 * Creates a {@link RefWatcher} instance and makes it available through {@link
* LeakCanary#installedRefWatcher()}.
*
* Also starts watching activity references if {@link #watchActivities(boolean)} was set to true.
*
* @throws UnsupportedOperationException if called more than once per Android process.
*/
public @NonNull RefWatcher buildAndInstall() {
if (LeakCanaryInternals.installedRefWatcher != null) {
throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
}
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
if (enableDisplayLeakActivity) {
LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);
}
if (watchActivities) {
ActivityRefWatcher.install(context, refWatcher);
}
if (watchFragments) {
FragmentRefWatcher.Helper.install(context, refWatcher);
}
}
LeakCanaryInternals.installedRefWatcher = refWatcher;
return refWatcher;
}
代码语言:txt复制 /** Creates a {@link RefWatcher}. */
代码语言:txt复制 public final RefWatcher build() {
代码语言:txt复制 if (isDisabled()) {
代码语言:txt复制 return RefWatcher.DISABLED;
代码语言:txt复制 }
代码语言:txt复制 if (heapDumpBuilder.excludedRefs == null) {
代码语言:txt复制 heapDumpBuilder.excludedRefs(defaultExcludedRefs());
代码语言:txt复制 }
代码语言:txt复制 HeapDump.Listener heapDumpListener = this.heapDumpListener;
代码语言:txt复制 if (heapDumpListener == null) {
代码语言:txt复制 heapDumpListener = defaultHeapDumpListener();
代码语言:txt复制 }
代码语言:txt复制 DebuggerControl debuggerControl = this.debuggerControl;
代码语言:txt复制 if (debuggerControl == null) {
代码语言:txt复制 debuggerControl = defaultDebuggerControl();
代码语言:txt复制 }
代码语言:txt复制 HeapDumper heapDumper = this.heapDumper;
代码语言:txt复制 if (heapDumper == null) {
代码语言:txt复制 heapDumper = defaultHeapDumper();
代码语言:txt复制 }
代码语言:txt复制 WatchExecutor watchExecutor = this.watchExecutor;
代码语言:txt复制 if (watchExecutor == null) {
代码语言:txt复制 watchExecutor = defaultWatchExecutor();
代码语言:txt复制 }
代码语言:txt复制 GcTrigger gcTrigger = this.gcTrigger;
代码语言:txt复制 if (gcTrigger == null) {
代码语言:txt复制 gcTrigger = defaultGcTrigger();
代码语言:txt复制 }
代码语言:txt复制 if (heapDumpBuilder.reachabilityInspectorClasses == null) {
代码语言:txt复制 heapDumpBuilder.reachabilityInspectorClasses(defaultReachabilityInspectorClasses());
代码语言:txt复制 }
代码语言:txt复制 return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
代码语言:txt复制 heapDumpBuilder);
代码语言:txt复制 }
build()方法,这个方法主要是配置一些东西,先大概了解一下,后面用到再说,下面是几个配置项目。
- watchExecutor : 线程控制器,在 onDestroy()之后并且主线程空闲时执行内存泄漏检测
- debuggerControl: 判断是否处于调试模式,调试模式中不会进行内存泄漏检测
- gcTrigger: 用于GC
- watchExecutor首次检测到可能的内存泄漏,会主动进行GC,GC之后会再检测一次,仍然泄漏的判定为内存泄漏,进行后续操作
- heapDumper: dump内存泄漏处的heap信息,写入hprof文件
- heapDumpListener: 解析完hprof文件并通知DisplayLeakService弹出提醒
- excludedRefs: 排除可以忽略的泄漏路径
LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class,
true);
这行代码主要是为了开启LeakCanary的应用,显示其图标.
具体实现如下:
代码语言:txt复制#LeakCanaryInternals.java
代码语言:txt复制 public static void setEnabledAsync(Context context, final Class<?> componentClass,
代码语言:txt复制 final boolean enabled) {
代码语言:txt复制 final Context appContext = context.getApplicationContext();
代码语言:txt复制 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
代码语言:txt复制 @Override public void run() {
代码语言:txt复制 setEnabledBlocking(appContext, componentClass, enabled);
代码语言:txt复制 }
代码语言:txt复制 });
代码语言:txt复制 }
代码语言:txt复制 public static void setEnabledBlocking(Context appContext, Class<?> componentClass,
代码语言:txt复制 boolean enabled) {
代码语言:txt复制 ComponentName component = new ComponentName(appContext, componentClass);
代码语言:txt复制 PackageManager packageManager = appContext.getPackageManager();
代码语言:txt复制 int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED;
代码语言:txt复制 // Blocks on IPC.
代码语言:txt复制 packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP);
代码语言:txt复制 }
接下来是重点:
ActivityRefWatcher.install(context, refWatcher);
源码如下:
代码语言:txt复制#ActivityRefWatcher.java
代码语言:txt复制public final class ActivityRefWatcher {
代码语言:txt复制 public static void installOnIcsPlus(@NonNull Application application,
代码语言:txt复制 @NonNull RefWatcher refWatcher) {
代码语言:txt复制 install(application, refWatcher);
代码语言:txt复制 }
代码语言:txt复制 public static void install(@NonNull Context context, @NonNull RefWatcher refWatcher) {
代码语言:txt复制 Application application = (Application) context.getApplicationContext();
代码语言:txt复制 ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
代码语言:txt复制 application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks);
代码语言:txt复制 }
代码语言:txt复制//注释1:Activity生命周期回调接口
代码语言:txt复制 private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
代码语言:txt复制 new ActivityLifecycleCallbacksAdapter() {
代码语言:txt复制 @Override public void onActivityDestroyed(Activity activity) {
代码语言:txt复制 //注释2:监听到Activity销毁的时候执行
代码语言:txt复制 refWatcher.watch(activity);
代码语言:txt复制 }
代码语言:txt复制 };
代码语言:txt复制 private final Application application;
代码语言:txt复制 private final RefWatcher refWatcher;
代码语言:txt复制 private ActivityRefWatcher(Application application, RefWatcher refWatcher) {
代码语言:txt复制 this.application = application;
代码语言:txt复制 this.refWatcher = refWatcher;
代码语言:txt复制 }
代码语言:txt复制 public void watchActivities() {
代码语言:txt复制 // Make sure you don't get installed twice.
代码语言:txt复制 stopWatchingActivities();
代码语言:txt复制 application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
代码语言:txt复制 }
代码语言:txt复制 public void stopWatchingActivities() {
代码语言:txt复制 application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
代码语言:txt复制 }
代码语言:txt复制}
我们主要看注释2:整个LeakCanary最核心的思路就在这儿。
代码语言:txt复制/**
代码语言:txt复制 * Watches references that should become weakly reachable. When the {@link RefWatcher} detects that
* a reference might not be weakly reachable when it should, it triggers the {@link HeapDumper}.
*
* <p>This class is thread-safe: you can call {@link #watch(Object)} from any thread.
*/
public final class RefWatcher {
代码语言:txt复制 public static final RefWatcher DISABLED = new RefWatcherBuilder<>().build();
代码语言:txt复制 private final WatchExecutor watchExecutor;
代码语言:txt复制 private final DebuggerControl debuggerControl;
代码语言:txt复制 private final GcTrigger gcTrigger;
代码语言:txt复制 private final HeapDumper heapDumper;
代码语言:txt复制 private final HeapDump.Listener heapdumpListener;
代码语言:txt复制 private final HeapDump.Builder heapDumpBuilder;
代码语言:txt复制 private final Set<String> retainedKeys;
代码语言:txt复制 private final ReferenceQueue<Object> queue;
代码语言:txt复制 RefWatcher(WatchExecutor watchExecutor, DebuggerControl debuggerControl, GcTrigger gcTrigger,
代码语言:txt复制 HeapDumper heapDumper, HeapDump.Listener heapdumpListener, HeapDump.Builder heapDumpBuilder) {
代码语言:txt复制 this.watchExecutor = checkNotNull(watchExecutor, "watchExecutor");
代码语言:txt复制 this.debuggerControl = checkNotNull(debuggerControl, "debuggerControl");
代码语言:txt复制 this.gcTrigger = checkNotNull(gcTrigger, "gcTrigger");
代码语言:txt复制 this.heapDumper = checkNotNull(heapDumper, "heapDumper");
代码语言:txt复制 this.heapdumpListener = checkNotNull(heapdumpListener, "heapdumpListener");
代码语言:txt复制 this.heapDumpBuilder = heapDumpBuilder;
代码语言:txt复制 retainedKeys = new CopyOnWriteArraySet<>();
代码语言:txt复制 queue = new ReferenceQueue<>();
代码语言:txt复制 }
代码语言:txt复制 /**
代码语言:txt复制 * Identical to {@link #watch(Object, String)} with an empty string reference name.
*
* @see #watch(Object, String)
*/
public void watch(Object watchedReference) {
watch(watchedReference, "");
}
代码语言:txt复制 /**
代码语言:txt复制 * Watches the provided references and checks if it can be GCed. This method is non blocking,
* the check is done on the {@link WatchExecutor} this {@link RefWatcher} has been constructed
* with.
*
* @param referenceName An logical identifier for the watched object.
*/
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);
代码语言:txt复制 ensureGoneAsync(watchStartNanoTime, reference);
代码语言:txt复制 }
代码语言:txt复制 /**
代码语言:txt复制 * LeakCanary will stop watching any references that were passed to {@link #watch(Object, String)}
* so far.
*/
public void clearWatchedReferences() {
retainedKeys.clear();
}
代码语言:txt复制 boolean isEmpty() {
代码语言:txt复制 removeWeaklyReachableReferences();
代码语言:txt复制 return retainedKeys.isEmpty();
代码语言:txt复制 }
代码语言:txt复制 HeapDump.Builder getHeapDumpBuilder() {
代码语言:txt复制 return heapDumpBuilder;
代码语言:txt复制 }
代码语言:txt复制 Set<String> getRetainedKeys() {
代码语言:txt复制 return new HashSet<>(retainedKeys);
代码语言:txt复制 }
代码语言:txt复制 private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
代码语言:txt复制 watchExecutor.execute(new Retryable() {
代码语言:txt复制 @Override public Retryable.Result run() {
代码语言:txt复制 return ensureGone(reference, watchStartNanoTime);
代码语言:txt复制 }
代码语言:txt复制 });
代码语言:txt复制 }
代码语言:txt复制 @SuppressWarnings("ReferenceEquality") // Explicitly checking for named null.
代码语言:txt复制 Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
代码语言:txt复制 long gcStartNanoTime = System.nanoTime();
代码语言:txt复制 long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
代码语言:txt复制 removeWeaklyReachableReferences();
代码语言:txt复制 if (debuggerControl.isDebuggerAttached()) {
代码语言:txt复制 // The debugger can create false leaks.
代码语言:txt复制 return RETRY;
代码语言:txt复制 }
代码语言:txt复制 if (gone(reference)) {
代码语言:txt复制 return DONE;
代码语言:txt复制 }
代码语言:txt复制 gcTrigger.runGc();
代码语言:txt复制 removeWeaklyReachableReferences();
代码语言:txt复制 if (!gone(reference)) {
代码语言:txt复制 long startDumpHeap = System.nanoTime();
代码语言:txt复制 long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
代码语言:txt复制 File heapDumpFile = heapDumper.dumpHeap();
代码语言:txt复制 if (heapDumpFile == RETRY_LATER) {
代码语言:txt复制 // Could not dump the heap.
代码语言:txt复制 return RETRY;
代码语言:txt复制 }
代码语言:txt复制 long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
代码语言:txt复制 HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
代码语言:txt复制 .referenceName(reference.name)
代码语言:txt复制 .watchDurationMs(watchDurationMs)
代码语言:txt复制 .gcDurationMs(gcDurationMs)
代码语言:txt复制 .heapDumpDurationMs(heapDumpDurationMs)
代码语言:txt复制 .build();
代码语言:txt复制 heapdumpListener.analyze(heapDump);
代码语言:txt复制 }
代码语言:txt复制 return DONE;
代码语言:txt复制 }
代码语言:txt复制 private boolean gone(KeyedWeakReference reference) {
代码语言:txt复制 return !retainedKeys.contains(reference.key);
代码语言:txt复制 }
代码语言:txt复制 private void removeWeaklyReachableReferences() {
代码语言:txt复制 // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
代码语言:txt复制 // reachable. This is before finalization or garbage collection has actually happened.
代码语言:txt复制 KeyedWeakReference ref;
代码语言:txt复制 while ((ref = (KeyedWeakReference) queue.poll()) != null) {
代码语言:txt复制 retainedKeys.remove(ref.key);
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制}
这个函数做的主要工作就是为需要进行泄漏检查的Activity创建一个带有唯一key标志的弱引用,并将这个弱引用key保存至retainedKeys中,然后将后面的工作交给watchExecutor来执行。这个watchExecutor在LeakCanary中是AndroidWatchExecutor的实例,调用它的execute方法实际上就是向主线程的消息队列中插入了一个IdleHandler消息,这个消息只有在对应的消息队列为空的时候才会去执行,因此RefWatcher的watch方法就保证了在主线程空闲的时候才会去执行ensureGone方法,防止因为内存泄漏检查任务而严重影响应用的正常执行。
这里引出了第一个知识点,弱引用和引用队列ReferenceQueue联合使用时,如果弱引用持有的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。即
KeyedWeakReference持有的Activity对象如果被垃圾回收,该对象就会加入到引用队列queue,我们看看RefreceQueue的javadoc:
代码语言:txt复制/**
代码语言:txt复制 * Reference queues, to which registered reference objects are appended by the
* garbage collector after the appropriate reachability changes are detected.
*
* @author Mark Reinhold
* @since 1.2
*/
// BEGIN Android-changed: Reimplemented to accomodate a different GC and compiler.
代码语言:txt复制public class ReferenceQueue<T>
重点是最后一句:ensureGoneAysnc,看字面意思,异步确保消失。这里我们先不看代码,如果自己设计一套检测方案的话,怎么想?其实很简单,就是在Activity
onDestory以后,我们等一会,检测一下这个Activity有没有被回收,那么问题来了,什么时候检测?怎么检测?这也是本框架的核心和难点。
LeakCanary是这么做的:onDestroy以后,一旦主线程空闲下来,延时5秒执行一个任务:先判断Activity有没有被回收?如果已经回收了,说明没有内存泄漏,如果还没回收,我们进一步确认,手动触发一下gc,然后再判断有没有回收,如果这次还没回收,说明Activity确实泄漏了,接下来把泄漏的信息展示给开发者就好了。
我们看代码实现:
代码语言:txt复制 private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
代码语言:txt复制 watchExecutor.execute(new Retryable() {
代码语言:txt复制 @Override public Retryable.Result run() {
代码语言:txt复制 return ensureGone(reference, watchStartNanoTime);
代码语言:txt复制 }
代码语言:txt复制 });
代码语言:txt复制 }
这里的watchExecutor是AndroidWatchExecutor,看代码:
代码语言:txt复制/**
代码语言:txt复制 * {@link WatchExecutor} suitable for watching Android reference leaks. This executor waits for the
* main thread to be idle then posts to a serial background thread with the delay specified by
* {@link AndroidRefWatcherBuilder#watchDelay(long, TimeUnit)}.
*/
public final class AndroidWatchExecutor implements WatchExecutor {
代码语言:txt复制 static final String LEAK_CANARY_THREAD_NAME = "LeakCanary-Heap-Dump";
代码语言:txt复制 private final Handler mainHandler;
代码语言:txt复制 private final Handler backgroundHandler;
代码语言:txt复制 private final long initialDelayMillis;
代码语言:txt复制 private final long maxBackoffFactor;
代码语言:txt复制 public AndroidWatchExecutor(long initialDelayMillis) {
代码语言:txt复制 mainHandler = new Handler(Looper.getMainLooper());
代码语言:txt复制 HandlerThread handlerThread = new HandlerThread(LEAK_CANARY_THREAD_NAME);
代码语言:txt复制 handlerThread.start();
代码语言:txt复制 backgroundHandler = new Handler(handlerThread.getLooper());
代码语言:txt复制 this.initialDelayMillis = initialDelayMillis;
代码语言:txt复制 maxBackoffFactor = Long.MAX_VALUE / initialDelayMillis;
代码语言:txt复制 }
代码语言:txt复制 @Override public void execute(@NonNull Retryable retryable) {
代码语言:txt复制 if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
代码语言:txt复制 waitForIdle(retryable, 0);
代码语言:txt复制 } else {
代码语言:txt复制 postWaitForIdle(retryable, 0);
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 private void postWaitForIdle(final Retryable retryable, final int failedAttempts) {
代码语言:txt复制 mainHandler.post(new Runnable() {
代码语言:txt复制 @Override public void run() {
代码语言:txt复制 waitForIdle(retryable, failedAttempts);
代码语言:txt复制 }
代码语言:txt复制 });
代码语言:txt复制 }
代码语言:txt复制 private void waitForIdle(final Retryable retryable, final int failedAttempts) {
代码语言:txt复制 // This needs to be called from the main thread.
代码语言:txt复制 Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
代码语言:txt复制 @Override public boolean queueIdle() {
代码语言:txt复制 postToBackgroundWithDelay(retryable, failedAttempts);
代码语言:txt复制 return false;
代码语言:txt复制 }
代码语言:txt复制 });
代码语言:txt复制 }
代码语言:txt复制 private void postToBackgroundWithDelay(final Retryable retryable, final int failedAttempts) {
代码语言:txt复制 long exponentialBackoffFactor = (long) Math.min(Math.pow(2, failedAttempts), maxBackoffFactor);
代码语言:txt复制 long delayMillis = initialDelayMillis * exponentialBackoffFactor;
代码语言:txt复制 backgroundHandler.postDelayed(new Runnable() {
代码语言:txt复制 @Override public void run() {
代码语言:txt复制 Retryable.Result result = retryable.run();
代码语言:txt复制 if (result == RETRY) {
代码语言:txt复制 postWaitForIdle(retryable, failedAttempts 1);
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 }, delayMillis);
代码语言:txt复制 }
代码语言:txt复制}
这里有第二个知识点,IdleHandler,这个东西是干嘛的,其实看名字就知道了,就是当主线程空闲的时候,如果设置了这个东西,就会执行它的queueIdle()方法,所以这个方法就是在onDestory以后,一旦主线程空闲了,就会执行,然后我们看它执行了啥:
private void postToBackgroundWithDelay(final Retryable retryable, final int failedAttempts) {
代码语言:txt复制 long exponentialBackoffFactor = (long) Math.min(Math.pow(2, failedAttempts), maxBackoffFactor);
代码语言:txt复制 long delayMillis = initialDelayMillis * exponentialBackoffFactor;
代码语言:txt复制 backgroundHandler.postDelayed(new Runnable() {
代码语言:txt复制 @Override public void run() {
代码语言:txt复制 Retryable.Result result = retryable.run();
代码语言:txt复制 if (result == RETRY) {
代码语言:txt复制 postWaitForIdle(retryable, failedAttempts 1);
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 }, delayMillis);
代码语言:txt复制 }
延时5秒执行retryable的run(),注意,因为这里是backgroundHandler post出来的,所以是下面的run 是在子线程执行的。
ensureGone(reference,
watchStartNanoTime),在看它干了啥之前,我们先理下思路,前面onDestory以后,AndroidWatchExecutor这个东西执行excute方法,这个方法让主线程在空闲的时候发送了一个延时任务,该任务在5秒延时后在一个子线程执行。理清了思路,我们看看这个任务是怎么执行的。
代码语言:txt复制 Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
代码语言:txt复制 long gcStartNanoTime = System.nanoTime();
代码语言:txt复制 long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
代码语言:txt复制 removeWeaklyReachableReferences();
代码语言:txt复制 if (debuggerControl.isDebuggerAttached()) {
代码语言:txt复制 // The debugger can create false leaks.
代码语言:txt复制 return RETRY;
代码语言:txt复制 }
代码语言:txt复制 if (gone(reference)) {
代码语言:txt复制 return DONE;
代码语言:txt复制 }
代码语言:txt复制 gcTrigger.runGc(); // 手动执行一次gc
代码语言:txt复制 removeWeaklyReachableReferences();
代码语言:txt复制 if (!gone(reference)) {
代码语言:txt复制 long startDumpHeap = System.nanoTime();
代码语言:txt复制 long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
代码语言:txt复制 File heapDumpFile = heapDumper.dumpHeap();
代码语言:txt复制 if (heapDumpFile == RETRY_LATER) {
代码语言:txt复制 // Could not dump the heap.
代码语言:txt复制 return RETRY;
代码语言:txt复制 }
代码语言:txt复制 long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
代码语言:txt复制 HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
代码语言:txt复制 .referenceName(reference.name)
代码语言:txt复制 .watchDurationMs(watchDurationMs)
代码语言:txt复制 .gcDurationMs(gcDurationMs)
代码语言:txt复制 .heapDumpDurationMs(heapDumpDurationMs)
代码语言:txt复制 .build();
代码语言:txt复制 heapdumpListener.analyze(heapDump);
代码语言:txt复制 }
代码语言:txt复制 return DONE;
代码语言:txt复制 }
因为这个方法是在主线程中执行的,因此一般执行到这个方法中的时候之前被destroy的那个Activity的资源应该被JVM回收了,因此这个方法首先调用removeWeaklyReachableReferences方法来将引用
队列中存在的弱引用从retainedKeys中删除掉,这样,retainedKeys中保留的就是还没有被回收对象的弱引用key。之后再用gone方法来
判断我们需要检查的Activity的弱引用是否在retainedKeys中,如果没有,说明这个Activity对象已经被回收,检查结束。否则,
LeakCanary主动触发一次gc,再进行以上两个步骤,如果发现这个Activity还没有被回收,就认为这个Activity很有可能泄漏了,并dump出当前的内存文件供之后进行分析。
前面我们说过,5秒延迟后先看看有没有回收,如果回收了,直接返回,没有发生内存泄漏,如果没有回收,触发GC,gc完成后,在此判断有没有回收,如果还没有回收,说明泄漏了,收集泄漏信息,展示给开发者。其中,removeWeaklyRechableReferences()和gone(reference)这两个方法配合,用来判断对象是否被回收了,看代码:
代码语言:txt复制 private void removeWeaklyReachableReferences() {
代码语言:txt复制 // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
代码语言:txt复制 // reachable. This is before finalization or garbage collection has actually happened.
代码语言:txt复制 KeyedWeakReference ref;
代码语言:txt复制 while ((ref = (KeyedWeakReference) queue.poll()) != null) {
代码语言:txt复制 retainedKeys.remove(ref.key);
代码语言:txt复制 }
代码语言:txt复制 }
通过知识点1知道:被回收的对象都会放到设置的引用队列queue中,我们从queue中拿出所有的ref,根据他们的key匹配retainedKeys集合中的元素并删除。然后在gone()函数里面判断key是否被移除.
代码语言:txt复制 private boolean gone(KeyedWeakReference reference) {
代码语言:txt复制 return !retainedKeys.contains(reference.key);
代码语言:txt复制 }
这个方法挺巧妙的,retainedKeys集合了所有destoryed了的但没有被回收的Activity的key,这个集合可以用来判断一个Activity有没有被回收,但是判断之前需要用removeWeaklyReachableReferences()这个方法更新一下。