First clarify a concept new WeakReference(object, ReferenceQueue)

Parameter Description Object: Indicates any object ReferenceQueue: indicates a queue

When object is recovered by GC, the new WeakReference above will be added to its parameter ReferenceQueue queue (juejin.cn/post/695343…).

Leakcanary Process: Based on 1.5.4

1. Listen to the activity lifecycle LeakCanary. Install

public static RefWatcher install(Application application) { return refWatcher(application).listenerServiceClass(DisplayLeakService.class) ExcludedRefs (AndroidExcludedRefs. CreateAppDefaults (). The build ()). / / to monitor the activity life cycle buildAndInstall (); }Copy the code

2. Create a key and add it to the set after onDestroy, and then wrap the key and activity in a KeyedWeakReference object (REF for short).

Public void onActivityDestroyed(Activity Activity) {//destroy callback 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(); // save key retainedkeys. add(key); // wrap into ref final KeyedWeakReference Reference = new KeyedWeakReference(watchedReference, key, referenceName, queue); ensureGoneAsync(watchStartNanoTime, reference); }Copy the code

3. Send an idle message to the main thread when it is idle

private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) { watchExecutor.execute(new Retryable() { @Override public Retryable.Result run() { return ensureGone(reference, watchStartNanoTime); }}); } public AndroidRefWatcherBuilder watchDelay(long delay, TimeUnit unit) { return watchExecutor(new AndroidWatchExecutor(unit.toMillis(delay))); } void waitForIdle(final Retryable retryable, Final int failedAttempts {// Join the idle list 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 the run () {/ / here back to run the execution ensureGone Retryable. The Result result = retryable.run(); if (result == RETRY) { postWaitForIdle(retryable, failedAttempts + 1); } } }, delayMillis); }Copy the code

4. Check if there is a ref in the queue and delete the key from the set. Note here: When object is recovered by GC, weakReference object created will be added to the queue queue, so if it is found that the object has been recovered, there is no leakage.) Otherwise, after invoking system GC, we will look in the queue again, if there is still no leakage, and finally print the stack

Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) { long gcStartNanoTime = System.nanoTime(); long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime); / / here detection weakrefrence object is had in the queue, have succeeded in recycling and remove the key removeWeaklyReachableReferences (); if (debuggerControl.isDebuggerAttached()) { // The debugger can create false leaks. return RETRY; } if (gone(reference)) {return DONE; if (gone(reference)) {return DONE; } // call gc gctrigger.rungc (); / / testing removeWeaklyReachableReferences again (); // Key still exists indicating that there is no weakrefrence object in queue (there may be leakage) if (! gone(reference)) { long startDumpHeap = System.nanoTime(); long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime); // Print stack 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; }Copy the code

reference