美文网首页
LeakCanary原理

LeakCanary原理

作者: gczxbb | 来源:发表于2019-03-20 16:25 被阅读0次

一、源码

LeakCanary内存分析模块,独立进程,包名:leakcanary,保持app进程独立。
在Application类执行LeakCanary.install(this)方法。

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

refWatcher()方法,生成AndroidRefWatcherBuilder建造者,buildAndInstall()方法,创建RefWatcher对象,Ref观察者监控引用对象。
DisplayLeakService服务,消息通知栏。

public RefWatcher buildAndInstall() {
    RefWatcher refWatcher = build();
    if (refWatcher != DISABLED) {
        if (watchActivities) {
            ActivityRefWatcher.install(context, refWatcher);
        }
        if (watchFragments) {
            FragmentRefWatcher.Helper.install(context, refWatcher);
        }
    }
    LeakCanaryInternals.installedRefWatcher = refWatcher;
    return refWatcher;
}

ActivityRefWatcher观察Activity,FragmentRefWatcher观察Fragment,build()方法创建RefWatcher,返回赋值给静态对象LeakCanaryInternals。
ActivityRefWatcher类的install()方法。

public static void install(Context context, RefWatcher refWatcher) {
    Application application = (Application) context.getApplicationContext();
    ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
    application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks);
}

Application类registerActivityLifecycleCallbacks()方法,监听所有Activity生命周期回调,仅重写onActivityDestroyed方法,当关闭一个Activity(销毁)时,会触发此方法。

private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
      new ActivityLifecycleCallbacksAdapter() {
        @Override public void onActivityDestroyed(Activity activity) {
          refWatcher.watch(activity);
        }
};

Activity组件销毁时,RefWatcher类的watch()方法分析跟踪,观察该Activity组件对象是否会被gc回收。

二、监控原理

watch(Object)方法,观察Object对象是否被回收,(监控的Activity对象)。

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

创建一个KeyedWeakReference弱引用(继承WeakReference),生成key,将代表弱引用的key加入retainedKeys列表。

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

WeakReference构造方法,弱引用对象,关联ReferenceQueue队列,父类Reference内部ReferenceQueue,Reference类enqueue()方法,向队列插入本身。

public boolean enqueue() {
    return queue != null && queue.enqueue(this);
}
Reference的ReferenceQueue
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
    watchExecutor.execute(new Retryable() {
      @Override public Retryable.Result run() {
        return ensureGone(reference, watchStartNanoTime);
      }
    });
}

ensureGoneAsync方法,WatchExecutor执行者触发ensureGone()方法。

Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
    removeWeaklyReachableReferences();
    
    if (gone(reference)) {
        return DONE;
    }
    gcTrigger.runGc();
    removeWeaklyReachableReferences();
    if (!gone(reference)) {
        ...
        File heapDumpFile = heapDumper.dumpHeap();

        HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
                .referenceName(reference.name)
                .watchDurationMs(watchDurationMs)
                .gcDurationMs(gcDurationMs)
                .heapDumpDurationMs(heapDumpDurationMs)
                .build();

        heapdumpListener.analyze(heapDump);
    }
    return DONE;
}

removeWeaklyReachableReferences()方法,从ReferenceQueue队列poll(),(回收的弱引用对象被加入ReferenceQueue队列),表示对象被gc,从列表retainedKeys删除对应key键值,gone()方法,判断retainedKeys是否包含key。

Reference和ReferenceQueue
当弱引用Reference关联对象被回收,虚拟机将该弱引用加入ReferenceQueue队列,只需判断在这个队列中是否包含弱引用即可。
Reference类的enquque()方法,向Reference内部队列ReferenceQueue添加。

gone()方法,ReferenceQueue队列弱引用是空时,对象未回收是可达的,手动gc操作。

@Override 
public void runGc() {
    Runtime.getRuntime().gc();
    enqueueReferences();
    System.runFinalization();
}

Runtimel类gc()操作,再一次执行removeWeaklyReachableReferences()方法和gone()方法,当retainedKeys不包含该若引用key时,说明对象被gc。
两次回收判断(包括一次gc后),如果都判定未回收,大概率是无法回收,说明这个对象存在内存泄漏。

三、泄漏处理

检测到泄漏时,dumpHeap生成一个文件。HeapDump的Listener的analyze方法,分析的是HeapDump对象,ServiceHeapDumpListener继承了Listener接口,启动一个HeapAnalyzerService服务,继承IntentService,在单独进程中分析。利用HeapAnalyzer,内部采用mat对内存进行分析并生成结果。
在分析时,分为findLeakingReference与findLeakTrace来查找泄漏的引用与轨迹,根据GCRoot开始按树形结构依次建议当前引用的轨迹信息。
开启内存泄漏查看页面DisplayLeakActivity。

四、总结

1,注册ActivityLifecycleCallbacks监听回调Activity销毁方法,RefWathcer类分析观察Activity对象。

2,虚拟机将回收的Reference弱引用加入其关联的ReferenceQueue队列,通过队列中的弱引用判定对象是否被回收,

3,每一个监控对象(watch方法)创建一个弱引用KeyedWeakReference。

4,弱引用Reference内部WeakReference队列,Reference的enqueue()方法,将自己加入队列。


任重而道远

相关文章

网友评论

      本文标题:LeakCanary原理

      本文链接:https://www.haomeiwen.com/subject/jgvzmqtx.html