LeakCanary 如何实现对内存泄露的监控?

一、Activity 生命周期回调方法 LifecycleCallbacks

Application 中注册 ActivityLifecycleCallbacks 时,可以监听到每个 Activity 的生命周期方法的执行。当 Activity 被销毁时,会回调到 onActivityDestroyed 方法,此时便是 LeakCanary 开始检测 Activity 是否泄露的时机。LeakCanary 通过 RefWatcher.watch(activity) 方法,判断刚刚调用了 onDestroy 方法的 Activity 是否泄露了。

二、弱引用 - WeakReference

WeakReference 继承自 Reference,其构造函数如下所示,每个 WeakReference 都会关联一个 ReferenceQueue,当 WeakReference 所指向的对象被 GC 后,这个 WeakReference 对象都会被放入与之相关联的 ReferenceQueue 中。

public abstract class Reference<T> {
	final ReferenceQueue<? super T> queue;
    Reference(T referent, ReferenceQueue<? super T> queue) {
        this.referent = referent;
        this.queue = queue;
    }
}
监控 Activity 是否泄露的逻辑

Activity 调用 onDestroy 方法后,理论上,接下来他应该被回收,这时指向 Activity 的弱引用应该被放入 ReferenceQueue 队列中,这时 ReferenceQueue 不应该为空,如果为空,说明 Activity 还没有被回收,发生了泄露。为了避免由于 gc 不及时带来的误判,LeakCanary 会进行一次手动 gc,代码如下所示

com/squareup/leakcanary/RefWatcher.java

	// 先清空 ReferenceQueue
    removeWeaklyReachableReferences();
    
	// 如果此时 activity 不可达了,说明已经被成功回收,没有泄露
    if (gone(reference) || debuggerControl.isDebuggerAttached()) {
      return;
    }
	// 手动 gc 
    gcTrigger.runGc();

	// 再次清空 ReferenceQueue 
    removeWeaklyReachableReferences();

	// 如果此时 activity 仍然可达,说明发生了 泄露,接下来会导出 heapDump 文件进行分析
	if (!gone(reference)) {
		...
	}
判断是否泄露的时机

IdleHandler 会在 UI 线程的 MessageQueue 为空时调用,由下面代码可知,会在主线程空闲时,5秒后派发一个判断是否泄露的任务 给 后台线程。

public final class AndroidWatchExecutor implements Executor {

	private static final int DELAY_MILLIS = 5000;
    //....
    private void executeDelayedAfterIdleUnsafe(final Runnable runnable) {
        // This needs to be called from the main thread.
        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
          @Override public boolean queueIdle() {
            backgroundHandler.postDelayed(runnable, DELAY_MILLIS);
            return false;
          }
        });
      }
  }
总结

LeakCanary 在 Activity 执行 onDestroy 后,利用 WeakReference 指向的对象被 GC 回收后会放入 ReferenceQueue 的特性,在后台线程中检测 Activity 是否泄露。当检测到泄露时,通过 AndroidHeapDumperdumpHeap 方法导出应用的栈信息到本地磁盘,然后在运行在私有进程:leakcanary 下的 HeapAnalyzerService 组件中对栈信息进行分析,找到泄露的引用和调用轨迹,最后把分析结果发送到通知栏,告知开发者存在内存泄漏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值