美文网首页
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