LeakCanary的工作原理

Java四大引用

  • 强引用:绝不回收
  • 软引用:内存不足才回收
  • 弱引用:碰到就回收
  • 虚引用:等价于没有引用,只是用来标识下指向的对象是否被回收。

WeakReference类

弱引用, 当一个对象仅仅被weak reference(弱引用)指向, 而没有任何其他strong reference(强引用)指向的时候, 如果这时GC运行, 那么这个对象就会被回收,不论当前的内存空间是否足够,这个对象都会被回收

WeakReference继承Reference,其中只有两个构造函数:

 /**
     * Creates a new weak reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new weak reference will refer to
     */
    public WeakReference(T referent) {
        super(referent);
    }
 /**
     * Creates a new weak reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new weak reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or null if registration is not required
     */
    public WeakReference(T referent, ReferenceQueue q) {
        super(referent, q);
    }
  • referent:被弱引用的对象,
  • ReferenceQueue:应用队列,在对象被回收后,会把弱引用对象,也就是WeakReference对象或者其子类的对象,放入队列ReferenceQueue中,注意不是被弱引用的对象,被弱引用的对象已经被回收了。
private void test() {
    // 创建一个对象(强引用)
    Object obj = new Object();
    // 创建一个弱引用,并指向这个对象,并且将引用队列传递给弱引用
    WeakReference reference = new WeakReference(obj, queue);
   
    // gc一次看看
    System.gc();
    此时循环打印引用队列为null
   
    while ((obj = queue.poll()) != null) {
        System.out.println(": " + obj);
    }
    // 设置obj为null,现在只有弱引用引用,可以被回收了
    obj = null;
    // 再进行gc,此时obj应该被回收了,那么queue里面应该有这个弱引用了
    System.gc();
    // 再打印队列不为
    Object obj;
    while ((obj = queue.poll()) != null) {
        System.out.println(": " + obj);
    }
}
 
 

LeakCanary工作原理

利用弱引用特性,检测Activity 的内存泄漏

  • LeakCanary.install(application);此时使用application进行registerActivityLifecycleCallbacks,从而来监听Activity的何时被destroy。

  • 在onActivityDestroyed(Activity activity)的回调中, 使用一个弱引用WeakReference指向这个activity,并且给这个弱引用指定一个引用队列queue,同时创建一个key来标识该activity。

  • 然后将检测的方法ensureGone()投递到空闲消息队列。

  • 当空闲消息执行的时候,去检测queue里面是否存在刚刚的弱引用,如果存在,则说明此activity已经被回收,就移除对应的key,没有内存泄漏发生。

  • 如果queue里不存在刚刚的弱引用,则手动进行一次gc。

  • gc之后再次检测queue里面是否存在刚刚的弱引用,如果不存在,则说明此activity还没有被回收,此时已经发生了内存泄漏,直接dump堆栈信息并打印日志,否则没有发生内存泄漏,流程结束。

空闲消息被执行的时候,大概率已经发生过gc,所以可以检测下gc后activity是否被回收。但是也可能还没发生gc,那么此时activity没有被回收是正常的,所以我们手动再gc一下,确保发生了gc,再去检测activity是否被回收,从而100%的确定是否发生了内存泄漏。

你可能感兴趣的:(LeakCanary的工作原理)