Leakcanary 源码分析<一>

本文详细解析了LeakCanary的内存泄漏检测机制,包括其如何通过监听Activity生命周期来发现潜在泄漏,并利用弱引用及堆分析定位具体泄漏源头。

首先进到LeakCanary 类里面的初始化静态方法。

 public static @NonNull RefWatcher install(@NonNull Application application) {
    return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
        .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
        .buildAndInstall();   }

refWatcher(application) 形成了AndroidRefWatcherBuilder。来看看这个。

 public @NonNull AndroidRefWatcherBuilder listenerServiceClass(
      @NonNull Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
    enableDisplayLeakActivity = DisplayLeakService.class.isAssignableFrom(listenerServiceClass);
    return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
  }

传入的是AbstractAnalysisResultService 实现类。很明显是堆复制监听使用。
excludedRefs(AndroidExcludedRefs.createAppDefaults().build()) 代表排除某些监听。这个后续会降到。最后落脚方法。

public @NonNull RefWatcher buildAndInstall() {
    if (LeakCanaryInternals.installedRefWatcher != null) {
      throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
    }
    //创建核心的RefWatch类。
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
      if (enableDisplayLeakActivity) {
        LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);
      }
      //观察Activity
      if (watchActivities) {
        ActivityRefWatcher.install(context, refWatcher);
      }
      //观察Fragment
      if (watchFragments) {
        FragmentRefWatcher.Helper.install(context, refWatcher);
      }
    }
    //赋值静态同步变量。
    LeakCanaryInternals.installedRefWatcher = refWatcher;
    return refWatcher;
  }

首先观察下如何发现Activity的内存泄露的。监听了 Application.ActivityLifecycleCallbacks。当Activity onDestroy的时候就可以开始检测内存泄露了,进入正题。

public static void install(@NonNull Context context, @NonNull 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);
        }
      };

watchedReference 就是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();
    retainedKeys.add(key);
    final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);

    ensureGoneAsync(watchStartNanoTime, reference);
  }

创建了KeyedWeakReference 的弱引用,这样不会导致Activity想释放而释放不掉的问题。
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);

ensureGoneAsync(watchStartNanoTime, reference);
  private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
    watchExecutor.execute(new Retryable() {
      @Override public Retryable.Result run() {
        return ensureGone(reference, watchStartNanoTime);
      }
    });
  }

watchExecutor实现类就是AndroidWatchExecutor。

@Override public void execute(@NonNull Retryable retryable) {
    //主线程执行,先看主线程执行吧。  
    if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
      waitForIdle(retryable, 0);
    } else {
     //子线程执行。
      postWaitForIdle(retryable, 0);
    }
  }
 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;
      }
    });
  }

注意这个IdleHandler 加入到主线程的Looper。这个代表了主线程开始空闲的时候,可以开始执行
postToBackgroundWithDelay(retryable, failedAttempts); 从这里我们已经走了一部分逻辑了。

  private 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() {
        Retryable.Result result = retryable.run();
        if (result == RETRY) {
          postWaitForIdle(retryable, failedAttempts + 1);
        }
      }
    }, delayMillis);
  }

retryable.run()就是这行的

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

      File heapDumpFile = heapDumper.dumpHeap();
      if (heapDumpFile == RETRY_LATER) {
        // Could not dump the heap.
        return RETRY;
      }
      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
//查询相关Activity的堆栈。    
      HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
          .referenceName(reference.name)
          .watchDurationMs(watchDurationMs)
          .gcDurationMs(gcDurationMs)
          .heapDumpDurationMs(heapDumpDurationMs)
          .build();
//进行分析。这个过程我就不分析了。
      heapdumpListener.analyze(heapDump);
    }
    return DONE;
  }

到这里LeakCanary具备分析内存泄露的原理就说明白了,核心的如何分析堆栈找出具体的类怎么泄露的,这里放到下面一章节去分析。
分析源码有个好处就是本来是一个黑盒模型,非得去查看里面具体的构造这么一个过程,你说很烦吧,确实烦,但是搞明白了,那也确实是爽。并且分析优秀框架过程其实无形中锻炼了你自己的代码水平,所以这是一条提升必然的逻辑了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值