美文网首页
LeakCanary 工作原理浅析

LeakCanary 工作原理浅析

作者: 大盗海洲 | 来源:发表于2019-06-16 11:18 被阅读0次

参考链接
Java内存问题 及 LeakCanary 原理分析
LeakCanary 工作原理浅析

通过 application.registerActivityLifecycleCallbacks 监听activity onActivityDestroy()
用过WeakReference+ReferenceQueue 存储当前activity 的引用,手动调用gc
然后判断ReferenceQueue队列是否含有此activity的引用,若不包含,说明被强引用,存在内存泄漏,然后导出heap dump 文件,用haha算法分析,在发送到通知栏里

public final class ActivityRefWatcher {
 public static void install(Context context, 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);
        }
      };
}
public final class RefWatcher {
 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);
//创建WeakReference
    final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);

    ensureGoneAsync(watchStartNanoTime, reference);
  }
}
public final class RefWatcher {

  @SuppressWarnings("ReferenceEquality") // Explicitly checking for named null.
  Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
    long gcStartNanoTime = System.nanoTime();
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);

    removeWeaklyReachableReferences();//先将引用尝试从队列中poll出来

    if (debuggerControl.isDebuggerAttached()) {//规避调试模式
      // The debugger can create false leaks.
      return RETRY;
    }
    if (gone(reference)) {//检测是否已经回收
      return DONE;
    }
        //如果没有被回收,则手动GC
    gcTrigger.runGc();
    removeWeaklyReachableReferences();//再次尝试poll,检测是否被回收
    if (!gone(reference)) {
// 还没有被回收,则dump堆信息,调起分析进程进行分析
      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);

      HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
          .referenceName(reference.name)
          .watchDurationMs(watchDurationMs)
          .gcDurationMs(gcDurationMs)
          .heapDumpDurationMs(heapDumpDurationMs)
          .build();

      heapdumpListener.analyze(heapDump);
    }
    return DONE;
  }

  private boolean gone(KeyedWeakReference reference) {
    return !retainedKeys.contains(reference.key);
  }

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

方法ensureGone中通过检测referenceQueue队列中的引用情况,来判断回收情况,通过手动GC来进一步确认回收情况。
整个过程肯定是个耗时卡UI的,整个过程会在WatchExecutor中执行的,那WatchExecutor又是在哪里执行的呢?
LeakCanary已经利用Looper机制做了一定优化,利用主线程空闲的时候执行检测任务,这里找到WatchExecutor的实现类,研究下原理:

public final class AndroidWatchExecutor implements WatchExecutor {

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

知识点

  • 用ActivityLifecycleCallback 监听activity生命周期
  • 用WeekReference+ReferenceQueue 来监听activity回收情况
  • Application 中可通过processName 判断是否任务执行进程
  • MessageQueue 中加入一个IdleHandler 来得到主线程空闲的回调
  • 只能监听activity里相关类内存泄漏,其他类无法使用,还得用MAT原始方法

相关文章

  • LeakCanary 工作原理浅析

    参考链接Java内存问题 及 LeakCanary 原理分析LeakCanary 工作原理浅析 通过 appli...

  • LeakCanary原理浅析

    LeakCanary原理浅析 1.LeakCanary简介 LeakCanary是一个Android和Java的内...

  • LeakCanary 工作原理浅析

    版权声明:本文为 咕咚 原创文章,可以随意转载,但必须在明确位置注明出处。作者博客地址: http://gudon...

  • LeakCanary原理浅析

    LeakCanary是Android内存泄漏的框架,作为一个“面试常见问题”,它一定有值得学习的地方,今天我们就讲...

  • LeakCanary实现原理浅析

    LeakCanary是一个在安卓平台上检测内存泄漏的工具库。 粗略的看了以下LeakCanary的实现原理。 Le...

  • 不是很深入的分析LeakCanary2.0

    Leakcanary2.0 Leakcanary 使用 原理 Reference 、ReferenceQueue ...

  • LeakCanary 内存泄漏原理完全解析

    LeakCanary 的工作原理是什么?跟我一起揭开它的神秘面纱。 一、 什么是LeakCanary LeakCa...

  • LeakCanary的工作原理

    Java四大引用 强引用:绝不回收 软引用:内存不足才回收 弱引用:碰到就回收 虚引用:等价于没有引用,只是用来标...

  • LeakCanary浅析

    一、使用 LeakCanary的使用非常的简单,两行代码搞定。当然也可以主动的添加需要监听的对象;LeakCana...

  • LeakCanary浅析

    说到内存泄漏,就必须提到LeakCanary. 这个利器,很方便的显示出内存泄漏的地方。在用到的过程中好奇怎...

网友评论

      本文标题:LeakCanary 工作原理浅析

      本文链接:https://www.haomeiwen.com/subject/csgwfctx.html