leakcanary原理解析

先明确一个概念
new WeakReference(object, ReferenceQueue)

参数说明
object: 任意对象
ReferenceQueue:一个队列 后边简称queue

当object被gc回收后 WeakReference将会加入到ReferenceQueue队列

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;
  }

复制代码

参考

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享