介绍
LeakCanary项目是为Java&Android开发提供的一个自动检测内存泄漏的工具,现在很多项目都在引入来提高代码质量,减少不必要的内存泄漏。

核心方法流程图
Android-LeakCanary原理分析

初始化流程
通过以下方法,将内存泄露框架添加到App中。
//在Application中添加内存监控框架
LeakCanary.install(this);
添加到App中,实际上就是构造了一个RefWatcher对象,并且设置Activity生命周期的监听。当Activity被销毁的时候,调用内存泄露框架进行监控。
//实现方法
public static RefWatcher install(Application application) {
  return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
        .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
        .buildAndInstall();
}

//生产AndroidRefWatcherBuilder内存泄露监控对象构造器
public static AndroidRefWatcherBuilder refWatcher(Context context) {
  return new AndroidRefWatcherBuilder(context);
}
在buildAndInstall()方法中,设置Activity生命周期的监听,并监控Acitivty内存泄露
public RefWatcher buildAndInstall() {
    //构造器生产RefWatcher对象
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
      //添加对Activity生命周期的监听
      ActivityRefWatcher.install((Application) context, refWatcher);
    }
    return refWatcher;
  }

  //ActivityRefWatcher.install()方法实现
  public static void install(Application application, RefWatcher refWatcher) {
    new ActivityRefWatcher(application, refWatcher).watchActivities();
  }

  public void watchActivities() {
    //注册Application生命周期监听
    application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
      @Override
      public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
      }

      @Override
      public void onActivityStarted(Activity activity) {
      }

      @Override
      public void onActivityResumed(Activity activity) {
      }

      @Override
      public void onActivityPaused(Activity activity) {
      }

      @Override
      public void onActivityStopped(Activity activity) {
      }

      @Override
      public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
      }

      @Override
      public void onActivityDestroyed(Activity activity) {
        //Activity.onDestory()回调时,被触发
        ActivityRefWatcher.this.onActivityDestroyed(activity);
      }
    });
  }

检查内存泄露
通过调用watch()方法,触发内存泄露检查。
 /**
   * 检测提供的(watchedReference)对象,是否存在内存泄露问题
   * @param watchedReference 被检测的对象
   * @param referenceName 引用名
   */
  public void watch(Object watchedReference, String referenceName) {
    if (this == DISABLED) {
      return;
    }
    //判空
    checkNotNull(watchedReference, "watchedReference");
    checkNotNull(referenceName, "referenceName");
    //开始检测内存泄漏的时间
    final long watchStartNanoTime = System.nanoTime();
    //生成检测对象的key
    String key = UUID.randomUUID().toString();
    //保存检测对象的key
    retainedKeys.add(key);
    //生成弱引用
    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);
      }
    });
  }

  //真正的内存泄露检测方法
  Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
    long gcStartNanoTime = System.nanoTime();
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
    //清除此时已经到ReferenceQueue中的弱引用
    removeWeaklyReachableReferences();
    // (1)如果当前检测的对象已经弱可达,那么说明对象已经不会泄漏
    if (gone(reference)) {
      return DONE;
    }
    //如果当前检测对象还没有改变其可达状态,GC()
    gcTrigger.runGc();
    //再次判断对象有没有进入队列
    removeWeaklyReachableReferences();
    //(2)如果此时还没有检测到入队列,那么有可能这个对象已经泄漏
    if (!gone(reference)) {
      //进入第二部,dump内存,分析内存快照
      //该部分,暂未分析
      long startDumpHeap = System.nanoTime();
      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
      File heapDumpFile = heapDumper.dumpHeap();
      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
      //处理分析结果
      heapdumpListener.analyze(
          new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
              gcDurationMs, heapDumpDurationMs));
    }
    return DONE;
  }

  //判断检测对象,是否已经被释放
  private boolean gone(KeyedWeakReference reference) {
    return !retainedKeys.contains(reference.key);
  }

  //如果为弱引用,在对象被释放的时候,就会将对象添加到ReferenceQueue中
  //通过调用ReferenceQueue.poll()来将已经释放的对象从map中移除
  private void removeWeaklyReachableReferences() {
    KeyedWeakReference ref;
    while ((ref = (KeyedWeakReference) queue.poll()) != null) {
      retainedKeys.remove(ref.key);
    }
  }

自动检测Activity内存泄露
由于上面的分析可得,在Activity.onDestory()回调的时候,会触发onActivityDestroyed()监听方法,下面是此方法内容
void onActivityDestroyed(Activity activity) {
    refWatcher.watch(activity);
}
也就是说,在Activity被销毁的时候,会自动检测此Activity是否存在内存泄露问题。

内存泄露框架划分
内存泄露框架存在三个模块,划分结构如下:
  • leakcanary-watcher: 这是一个通用的内存检测器,对外提供一个 RefWatcher#watch(Object watchedReference),可以看出,它不仅能够检测 Activity,还能监测任意常规的 Java Object 的泄漏情况。
  • leakcanary-android: 这个 module 是与 Android 世界的接入点,用来专门监测 Activity 的泄漏情况,内部使用了 application#registerActivityLifecycleCallbacks 方法来监听 onDestory 事件,然后利用 leakcanary-watcher 来进行弱引用+手动 GC 机制进行监控。
  • leakcanary-analyzer: 这个 module 提供了 HeapAnalyzer,用来对 dump 出来的内存进行分析并返回内存分析结果 AnalysisResult,内部包含了泄漏发生的路径等信息供开发者寻找定位。

相关文章: