LeakCanary解析

github地址:LeakCanary

使用很简单
In your build.gradle

dependencies {
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
  releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
  // Optional, if you use support library fragments:
  debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
}

In your Application class:

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    if (LeakCanary.isInAnalyzerProcess(this)) {
      // This process is dedicated to LeakCanary for heap analysis.
      // You should not init your app in this process.
      return;
    }
    LeakCanary.install(this);
    // Normal app init code...
  }
}

检查内存泄露的流程
由于在Android api 14的以上,才提供ActivityLifecycleCallbacks类,所以在14以下可以通过在Activity的onDestory方法中,调用ReWatch对象的watch方法来实现内存检查。

 ((ExampleApplication)getApplicationInfo()).getRefWatcher().watch(this);

简单说下流程

  • 通过监听activity 的生命周期。
  • 创建关联activity的KeyedWeakReference和ReferenceQueue对象,并且创建一个集合retainedKeys,该集合用来中保存当前activity的key值(key值是指区分每个activity的标识符),判断当前activity是否发生泄漏的关键,KeyedWeakReference,ReferenceQueue这俩个对象的主要作用是当activity销毁时,相关连的KeyedWeakReference引用也将消失,那么在ReferenceQueue中可以找到activity的引用对象。然后在retainedKeys中移除该activity,如果在retainedKeys中找不到当前activity的软引用对象,说明有内存泄露,然后通过分析hprof 文件 。
  • 分析完成之后发送通知到通知栏,
    下面分析下具体的实现:
  public static @NonNull RefWatcher install(@NonNull Application application) {
    return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
        .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
        .buildAndInstall();
  }

通过链式调用,refWatcher(application) 方法返回一个AndroidRefWatcherBuilder对象。

 public static @NonNull AndroidRefWatcherBuilder refWatcher(@NonNull Context context) {
    return new AndroidRefWatcherBuilder(context);
  }

AndroidRefWatcherBuilder ,是RefWatcherBuilder的子类,再看listenerServiceClass(DisplayLeakService.class),

 /**
   * 设置一个自定义的AbstractAnalysisResultService 去监听分析结果,
   * Sets a custom {@link AbstractAnalysisResultService} to listen to analysis results. This
   * overrides any call to {@link #heapDumpListener(HeapDump.Listener)}.
   */
  public @NonNull AndroidRefWatcherBuilder listenerServiceClass(
      @NonNull Class listenerServiceClass) {
    //listenerServiceClass 是不是DisplayLeakService 的子类或者接口
    enableDisplayLeakActivity = DisplayLeakService.class.isAssignableFrom(listenerServiceClass);
    return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
  }

enableDisplayLeakActivity表示是否默认显示泄露的activity,ServiceHeapDumpListener用来分析生成的hprof文件。excludedRefs(AndroidExcludedRefs.createAppDefaults().build()),排除掉Android系统层面导致的引用,这里有一些是由于厂商导致的,还有一些事系统本身就存在的,这个我们不用管的泄露问题。
最后再来看看 buildAndInstall()方法,

  /**
   * Creates a {@link RefWatcher} instance and makes it available through {@link
   * LeakCanary#installedRefWatcher()}.
   *
   * Also starts watching activity references if {@link #watchActivities(boolean)} was set to true.
   *
   * @throws UnsupportedOperationException if called more than once per Android process.
   */
  public @NonNull RefWatcher buildAndInstall() {
    //表示buildAndInstall 这个方法只能调用一次,因为下面已经重新赋值了的,
    if (LeakCanaryInternals.installedRefWatcher != null) {
      throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
    }
    //构建RefWatcher
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
      //开启一个组件,(动态注册一个DisplayLeakActivity)
      if (enableDisplayLeakActivity) {
        LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);
      }
      //将activity的生命周期和refWatcher对象关联起来
      if (watchActivities) {
        ActivityRefWatcher.install(context, refWatcher);
      }

    }
    //重新赋值
    LeakCanaryInternals.installedRefWatcher = refWatcher;
    return refWatcher;
  }

主要看构建 build()方法

 /** Creates a {@link RefWatcher}. */
  public final RefWatcher build() {
    if (isDisabled()) {
      return RefWatcher.DISABLED;
    }

//排除可以忽略的泄漏路径
    if (heapDumpBuilder.excludedRefs == null) {
      heapDumpBuilder.excludedRefs(defaultExcludedRefs());
    }
//解析完 hprof 文件,进行回调,并通知 DisplayLeakService 弹出提醒
    HeapDump.Listener heapDumpListener = this.heapDumpListener;
    if (heapDumpListener == null) {
      heapDumpListener = defaultHeapDumpListener();
    }
//判断是否处于调试模式,调试模式中不会进行内存泄漏检测
    DebuggerControl debuggerControl = this.debuggerControl;
    if (debuggerControl == null) {
      debuggerControl = defaultDebuggerControl();
    }
//dump 内存泄漏处的 heap 信息,写入 hprof 文件
    HeapDumper heapDumper = this.heapDumper;
    if (heapDumper == null) {
      heapDumper = defaultHeapDumper();
    }

//线程控制器,在 onDestroy() 之后并且主线程空闲时执行内存泄漏检测
    WatchExecutor watchExecutor = this.watchExecutor;
    if (watchExecutor == null) {
      watchExecutor = defaultWatchExecutor();
    }
// 用于 GC,watchExecutor 首次检测到可能的内存泄漏,会主动进行 GC,GC 之后会再检测一次,仍然泄漏的判定为内存泄漏,进行后续操作
    GcTrigger gcTrigger = this.gcTrigger;
    if (gcTrigger == null) {
      gcTrigger = defaultGcTrigger();
    }

    if (heapDumpBuilder.reachabilityInspectorClasses == null) {
      heapDumpBuilder.reachabilityInspectorClasses(defaultReachabilityInspectorClasses());
    }

    return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
        heapDumpBuilder);
  }

将RefWatcher 和activity关联起来ActivityRefWatcher.install(context, refWatcher);
看看具体的实现

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

可以看到在生命周期onActivityDestroyed 时,回调refwatcher调用watch方法。查看watch方法


  /**
   * Identical to {@link #watch(Object, String)} with an empty string reference name.
   *
   * @see #watch(Object, String)
   */
  public void watch(Object watchedReference) {
    watch(watchedReference, "");
  }

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();
    //添加到set集合
    retainedKeys.add(key);
    //创建KeyedWeakReference对象
    final KeyedWeakReference reference =
        new KeyedWeakReference(watchedReference, key, referenceName, queue);

    ensureGoneAsync(watchStartNanoTime, reference);
  }

这就是前面说的KeyedWeakReference和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);
      }
    });
  }

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

    if (debuggerControl.isDebuggerAttached()) {
      // The debugger can create false leaks.
      return RETRY;
    }
      // 判断 reference,即 activity 是否内回收了,若被回收了,直接返回
    if (gone(reference)) {
      return DONE;
    }
      // 调用 gc 方法进行垃圾回收
    gcTrigger.runGc();

      // 移除已经被回收的引用
    removeWeaklyReachableReferences();
      // activity 还没有被回收,证明发生内存泄露
    if (!gone(reference)) {
      long startDumpHeap = System.nanoTime();
      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
        // dump heap,并生成相应的 hprof 文件
      File heapDumpFile = heapDumper.dumpHeap();
        // dump the heap 失败的时候
      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;
  }

这里的 watchExecutor是在AndroidRefWatcherBuilder生产的。

  @Override protected @NonNull WatchExecutor defaultWatchExecutor() {
    return new AndroidWatchExecutor(DEFAULT_WATCH_DELAY_MILLIS);
  }

具体的实现execute()方法

 @Override public void execute(@NonNull Retryable retryable) {
    if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
      //如果是主线程就等到空闲
      waitForIdle(retryable, 0);
    } else {
      //非主线程等到空闲
      postWaitForIdle(retryable, 0);
    }
  }
 //在主线程中更新
  private void postWaitForIdle(final Retryable retryable, final int failedAttempts) {
    mainHandler.post(new Runnable() {
      @Override public void run() {
        waitForIdle(retryable, failedAttempts);
      }
    });
  }

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

最后发现都是调用的postToBackgroundWithDelay()这个方法,postToBackgroundWithDelay()这个方法是一个根据返回结果判断是否重复执行的方法,类似递归。

 // 取 Math.pow(2, failedAttempts), maxBackoffFactor 的最小值,maxBackoffFactor = Long.MAX_VALUE / 5,
    // 第一次执行的时候 failedAttempts 是 0 ,所以 exponentialBackoffFactor 是1
    long exponentialBackoffFactor = (long) Math.min(Math.pow(2, failedAttempts), maxBackoffFactor);
    // initialDelayMillis 的默认值是 5
    long delayMillis = initialDelayMillis * exponentialBackoffFactor;
    Log.e("info","exponentialBackoffFactor-->"+exponentialBackoffFactor+"delayMillis-->"+delayMillis);
    // 所以第一次延迟执行的时候是 5s,若
    backgroundHandler.postDelayed(new Runnable() {
      @Override public void run() {
        Retryable.Result result = retryable.run();
        if (result == RETRY) {
          // 过 result == RETRY,再次调用 postWaitForIdle,下一次的 delayMillis= 上一次的  delayMillis *2;
          postWaitForIdle(retryable, failedAttempts + 1);
        }
      }
    }, delayMillis);
  }

看下retryable.run()方法 。执行的正是ensureGone(reference, watchStartNanoTime)方法。判断其返回结果,看是否需要重复执行postWaitForIdle(retryable, failedAttempts + 1)。ensureGone()方法的执行原理就是整个leakcarany方法的检查泄漏的主要逻辑点,首先检查将ReferenceQueue˙中的软引用移除,再调用gc方法进行垃圾回收,在此将ReferenceQueue的软引用移除,如果还存在无法销毁的引用,那证明会导致内存泄漏。

你可能感兴趣的:(LeakCanary解析)