LeakCanary 的使用及原理分析(Activity内存泄露监测)

前言

Android 应用开发过程中,经常会遇到各种情况下的 Activity 内存泄露。一旦出现泄露,可能会引起应用内存占用过高,出现卡顿或者 OutOfMemoryError,所以在开发阶检测出内存泄露问题非常有必要。而 LeakCanary 是一个在开发阶段检测 Activity 内存泄露的一个利器。

应用接入

添加依赖

在 build.gradle 文件中,添加如下依赖,

dependencies {
  ...
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3’
  releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
  ...
}

注意:上面的使用的是 debugImplementation ,表示只会在 debug 构建时使用该依赖。而 releaseImplementation 表示在 release 构建时,使用此依赖,而 leakcanary-android-no-op 实际上没有做任何操作。

代码接入

一般在自定义 Application 类的 onCreate() 方法加入下面的代码即可,

if (BuildConfig.DEBUG) {
    // Memory leak analysis,Only valid on debug version
    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);
}

只有在 debug 版本时,才调用 LeakCanary.install() 方法。

当发生泄露时,会在通知栏有一个通知,点击进去后会看到下面一个界面,详细的展示了内存泄露的 trace,如下图,
在这里插入图片描述

实现原理

LeakCanary 的实现原理,主要依赖两个知识点,

  • android.app.Application.ActivityLifecycleCallbacks:应用中所有 Activity 生命周期检测
  • java.lang.ref.WeakReference 的两个参数构造方法:public WeakReference(T referent, ReferenceQueue<? super T> q)
ActivityLifecycleCallbacks 监控 Activity 的生命周期

LeakCanary 在 Application 中调用 install() 方法后,会通过 Application 注册 activity 生命周期回调接口,这样每个 Activity 的 onDestroy() 方法被调用的时候,LeakCanary 都能知道。具体的代码实现在LeakCanary 库的 ActivityRefWatcher 类中,

  1. lifecycleCallbacks 对象的实现
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
    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) {
        ActivityRefWatcher.this.onActivityDestroyed(activity);
      }
    };
  1. 注册 activity 的生命周期回调接口
public void watchActivities() {
  // Make sure you don't get installed twice.
  stopWatchingActivities();
  application.registerActivityLifecycleCallbacks(lifecycleCallbacks); //
}
WeakReference 观测 Activity 的引用状态

在 onActivityDestroyed 方法中,会使用 RefWatcher 来 watch 传入的 activity 对象,而 RefWatcher 类里面,会用到 WeakReference 的第二个构造函数,来观测 activity 对象的回收情况,核心代码如下,

final class KeyedWeakReference extends WeakReference<Object> {
  ...
}
private final ReferenceQueue<Object> queue;
public void watch(Object watchedReference, String referenceName) {
  ...
  final KeyedWeakReference reference =
      new KeyedWeakReference(watchedReference, key, referenceName, queue);
  ...
  ensureGoneAsync(watchStartNanoTime, reference);
}

从上面的实现可知,KeyedWeakReference 继承自 WeakReference,所以实际还是基于 WeakReference 第二个构造函数实现的。在构造 KeyedWeakReference 对象时,第二个参数传入的一个 ReferenceQueue。

在 watch() 方法最后,调用了 ensureGoneAsync() 方法,在这个方法中,会主动触发一次 gc,并且检测 ReferenceQueue 中是否包含该 activity 对象,如果不包含,表示这个 activity 被强引用,产生了内存泄露,这时就会把 heap 信息 dump 出来,并使用 haha 对 HeapDump 对象进行分析,得到分析结果后进行通知栏提示,核心代码如下,

Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
  ...
  gcTrigger.runGc(); //主动触发 gc
  removeWeaklyReachableReferences();
  if (!gone(reference)) {
    ...
    File heapDumpFile = heapDumper.dumpHeap();
    ...
    //分析HeapDump对象
    heapdumpListener.analyze(
        new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
            gcDurationMs, heapDumpDurationMs));
  }
  return DONE;
}

总结

LeakCanary 可以帮助开发者在调试阶段,方便的检测出 Activity 内存泄露问题。主要通过 Application.ActivityLifecycleCallbacks 和 java.lang.ref.WeakReference 这两个知识点来实现。当出现内存泄露时,通过 haha 来分析 dump heap,并提示用户。

参考链接:
https://gudong.name/2017/05/15/leakcanary-theory.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ToSimpleL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值