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 <tt>null</tt> if registration is not required
*/
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
- referent:被弱引用的对象,
- ReferenceQueue:应用队列,在对象被回收后,会把弱引用对象,也就是WeakReference对象或者其子类的对象,放入队列ReferenceQueue中,注意不是被弱引用的对象,被弱引用的对象已经被回收了。
private void test() {
// 创建一个对象(强引用)
Object obj = new Object();
// 创建一个弱引用,并指向这个对象,并且将引用队列传递给弱引用
WeakReference<Object> 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%的确定是否发生了内存泄漏。
网友评论