Leakcanary源码分析

1,310 阅读2分钟

介绍

Leakcanary是用于检测内存泄漏的库

在研究源码之前,需要一些jvm的前置知识

JVM如何回收内存

通过可达性算法,将不太容易回收的变量作为gc root,可回收的对象会与其形成一个引用链,如果没有在引用链上,即不可达,也就是没有回收的对象,造成内存泄漏

何为弱引用

弱引用表示对象标记为弱可达,一旦垃圾回收器扫描到,就会被gc,将对象通过WeakReference构造函数传入就可标记为弱可达,注意还有一个参数为ReferenceQueue(以下用RQ代替),是一个引用队列,被回收对象所引用的WeakReference对象会在gc时添加到队列中,可以利用这个特性,在强制gc后,判断如果引用队列中有值,证明发生了gc,没有产生内存泄漏;如果引用队列为空,则证明有内存泄漏产生

(以上其实就是Leakcanary的理论基础)

举个弱引用的例子

static class Num {
        int i;
        public Num(int i) {
            this.i = i;
        }

        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            Log.d(TAG, "finalize->" + i);
        }
    }

    public static void main(String[] args) {
        ReferenceQueue<Object> mRq;
        WeakReference<Num> mWeakReference = new WeakReference<>(new Num(126), mRq = new ReferenceQueue<>());
        Log.d(TAG, "GC前," + "num=" + mWeakReference.get().i + ",mRq=" + mRq.poll());
        Runtime.getRuntime().gc();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "GC后," + "num=" + mWeakReference.get() + ",mRq=" + mRq.poll());
    }

输出结果

正式分析

具备了以上前置知识,分析下几个问题

  • Leakcanary如果实现检测内存泄漏的
  • 如何做初始化工作

如何检测内存泄漏

  • 首先会构建一个包含引用对象(比如Activity和Fragemnt或者任何其他对象)和引用队列ReferenceQueue的弱引用对象,并将这个弱引用对象放到一个map中,如果发生了gc,弱引用对象会添加到RQ中
  • 此时将map中的值清空,如果仍然存在不为空的值,则就是没有被回收的对象,强制gc
  • 如果未回收对象仍然存在,则弹泄漏弹框通知并dump heap文件并通过shark来分析到gc root的最短路径

如何做初始化工作

比较有意思的地方是这个库并没有在项目中需要初始化,其实不然,是通过ContentProvider来进行初始化的,因为ContentProvider的调用时间是介于Application的onCreateattachBaseContext之间进行的,不过也存在一个问题就是对启动优化不太友好

博客