LeakCanary工作流程

什么时候开始检测泄漏
public static @NonNull RefWatcher install(@NonNull Application application) {
    return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
        .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
        .buildAndInstall();
}
public @NonNull RefWatcher buildAndInstall() {
    if (LeakCanaryInternals.installedRefWatcher != null) {
      throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
    }
    //初始化RefWatcher,RefWatcher主要是检测是否内存泄漏并且获取相关的hprof文件
    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;
}

在初始化完RefWatcher之后 调用ActivityRefWatcher.install(context, refWatcher)监听activity的ondestory,调用FragmentRefWatcher.Helper.install(context, refWatcher)监听fragment的onFragmentViewDestroyed和onFragmentDestroyed。

activity通过application.registerActivityLifecycleCallbacks()获取activity的ondestory事件。
fragment通过supportFragmentManager.registerFragmentLifecycleCallbacks获取fragment回调事件,该方法只在supportFragmentManager 和8.0以上的FragmentManager才有,所以8.0以下的android.app.Fragment是无法监听到泄漏的。

怎么检测泄漏

当知道activity或者fragment销毁之后。调用RefWatcher.watch(Object watchedReference),通过检测传入的引入是否被回收来判断内存是否泄漏

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);
    
    //获取hprof
      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;
    }

这里将检测的对象设置为弱引用,并且设置引用对列ReferenceQueue。
这样当弱引用对象被标记为finalizable,表示可以被回收,这时垃圾收集器就会把对象的弱引用放入ReferenceQueue队列中。

而检测对象是否可回收的方法

  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);
    }
  }
   private boolean gone(KeyedWeakReference reference) {
    return !retainedKeys.contains(reference.key);
  }

就是通过判断队列是否有相应的key来实现的。

怎么分析hprof文件

通过ServiceHeapDumpListener.analyze(@NonNull HeapDump heapDump)最终调用HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);

HeapAnalyzerService 是个前台服务 主要分析hprof文件并将相关数据放入AnalysisResult

@Override protected void onHandleIntentInForeground(@Nullable Intent intent) {
    if (intent == null) {
      CanaryLog.d("HeapAnalyzerService received a null intent, ignoring.");
      return;
    }
    String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA);
    HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA);

    HeapAnalyzer heapAnalyzer =
        new HeapAnalyzer(heapDump.excludedRefs, this, heapDump.reachabilityInspectorClasses);
    //具体使用[haha](https://github.com/square/haha)分析hprof文件
    AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey,
        heapDump.computeRetainedHeapSize);
    //把heapDump 和heapAnalyzer 存储在本地,以xx.result文件结尾
    AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
  }

AbstractAnalysisResultService也是一个前台服务 ,他的工作是:

读取刚刚存储的xx.result文件,以当前时间为名字重命名,方便按照时间排序显示。
获取HeapDump和AnalysisResult里面重要的文字 显示在通知栏。

当点击通知栏的时候调用DisplayLeakActivity显示具体的信息。


在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值