leakCanary监听原理

WeakReference知识

weakReference在java为弱应用对象,在系统发生gc的时候,被weakReference引用的对象会被回收(必然)。
构造方法如下:

public class WeakReference<T> extends Reference<T> {

public WeakReference(T r) {
    super(r, null);
}

public WeakReference(T r, ReferenceQueue<? super T> q) {
    super(r, q);
}
}

其中ReferenceQueue是个队列,这个参数比较重要,在系统发生gc的时候会回收被引用的对象,然后会把WeakReference这个入队到ReferenceQueue中,注意不是被引用的对象,因为它已经被回收了。

LeakCanary原理

我们会在Application中调用静态方法install,其中是通过构建者模式创建了AndroidRefWatcherBuilder对象

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

其中DisplayLeakService是个服务(继承IntentService),监听dump的信息并分析日志文件,会执行toast和通知栏。
excludedRefs中排除一些国内厂商的系统泄露问题
最后会执行buildAndInstall

  public RefWatcher buildAndInstall() {
		RefWatcher refWatcher = build();
	    if (refWatcher != DISABLED) {
	      LeakCanary.enableDisplayLeakActivity(context);
	      ActivityRefWatcher.install((Application) context, refWatcher);
	    }
	    return refWatcher;
}

其中ActivityRefWatcher.install最后会调用 ActivityRefWatcher.watchActivities方法

  application.registerActivityLifecycleCallbacks(lifecycleCallbacks);

其中lifecycleCallbacks变量就是Activity的回调周期函数,这样就可以监听页面的情况,其中lifecycleCallbacks只对onActivityDestroyed进行处理,也就是页面销毁时候检测

    @Override public void onActivityDestroyed(Activity activity) {
      ActivityRefWatcher.this.onActivityDestroyed(activity);
    }

onActivityDestroyed最终会调用refWatcher的watch方法

  void onActivityDestroyed(Activity activity) {
      refWatcher.watch(activity);
  }

watch源码

  public void watch(Object watchedReference, String referenceName) {
    if (this == DISABLED) {
      return;
    }
    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);
  }

retainedKeys它是个Set集合,存放随机key,它和KeyedWeakReference的key中对应,以Activity为例我们可以看出,每个Activty对应一个key和一个弱引用对象。

Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
	    long gcStartNanoTime = System.nanoTime();
	    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
	    //清除已回收的对象
	    removeWeaklyReachableReferences();
	    //debug模式直接返回
	    if (debuggerControl.isDebuggerAttached()) {
	      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) {
	        return RETRY;
	      }
	      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
	      heapdumpListener.analyze(
	          new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
	              gcDurationMs, heapDumpDurationMs));
	    }
	    return DONE;
}
  //判断retainedKeys是否有未回收的对象
   private boolean gone(KeyedWeakReference reference) {
    return !retainedKeys.contains(reference.key);
  }
  //根据queue存在的对象移除retainedKeys中的值
  private void removeWeaklyReachableReferences() {
    KeyedWeakReference ref;
    while ((ref = (KeyedWeakReference) queue.poll()) != null) {
      retainedKeys.remove(ref.key);
    }
  }

确定是否回收,根据弱引用的queue是否有值,如果有则移除retainedKeys中的对象。
步骤:

1.根据弱引用的queue中的对象key执行remove操作 删除retainedKeys集合中的值
2.判断retainedKeys是否有存在该对象,若不存在结束操作
3.手动执行gc
4.再执行1,2操作
5.此时若retainedKeys还有值则可判断存在内存泄漏,执行后续操作

若发生内存泄漏会执行 dumpHeap方法,通过 Debug.dumpHprofData 方法获取heapDumpFile,然后启动服务分析.hrof 最后会使用squaredup的haha库进行堆分析

	  public static void runAnalysis(Context context, HeapDump heapDump,
	      Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
        //HeapAnalyzerService是分析核心服务
        //listenerServiceClass是通知栏通知
	    Intent intent = new Intent(context, HeapAnalyzerService.class);
	    intent.putExtra(LISTENER_CLASS_EXTRA, listenerServiceClass.getName());
	    intent.putExtra(HEAPDUMP_EXTRA, heapDump);
	    context.startService(intent);
	  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值