Java四大引用
- 強引用:絕不回收
- 軟引用:內存不足才回收
- 弱引用:碰到就回收
- 虛引用:等價于沒有引用,只是用來標識下指向的對象是否被回收。
WeakReference類
弱引用, 當一個對象僅僅被weak reference(弱引用)指向, 而沒有任何其他strong reference(強引用)指向的時候, 如果這時GC運行, 那么這個對象就會被回收关拒,不論當前的內存空間是否足夠,這個對象都會被回收
WeakReference繼承Reference,其中只有兩個構造函數(shù):
/**
* 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() {
// 創(chuàng)建一個對象(強引用)
Object obj = new Object();
// 創(chuàng)建一個弱引用逆害,并指向這個對象头镊,并且將引用隊列傳遞給弱引用
WeakReference<Object> reference = new WeakReference(obj, queue);
// gc一次看看
System.gc();
此時循環(huán)打印引用隊列為null
while ((obj = queue.poll()) != null) {
System.out.println(": " + obj);
}
// 設置obj為null,現(xiàn)在只有弱引用引用魄幕,可以被回收了
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坛芽,從而來監(jiān)聽Activity的何時被destroy。
在onActivityDestroyed(Activity activity)的回調中队丝, 使用一個弱引用WeakReference指向這個activity靡馁,并且給這個弱引用指定一個引用隊列queue,同時創(chuàng)建一個key來標識該activity机久。
然后將檢測的方法ensureGone()投遞到空閑消息隊列臭墨。
當空閑消息執(zhí)行的時候,去檢測queue里面是否存在剛剛的弱引用膘盖,如果存在胧弛,則說明此activity已經被回收尤误,就移除對應的key,沒有內存泄漏發(fā)生结缚。
如果queue里不存在剛剛的弱引用损晤,則手動進行一次gc。
gc之后再次檢測queue里面是否存在剛剛的弱引用红竭,如果不存在尤勋,則說明此activity還沒有被回收,此時已經發(fā)生了內存泄漏茵宪,直接dump堆棧信息并打印日志最冰,否則沒有發(fā)生內存泄漏,流程結束稀火。
空閑消息被執(zhí)行的時候暖哨,大概率已經發(fā)生過gc,所以可以檢測下gc后activity是否被回收凰狞。但是也可能還沒發(fā)生gc篇裁,那么此時activity沒有被回收是正常的,所以我們手動再gc一下赡若,確保發(fā)生了gc达布,再去檢測activity是否被回收,從而100%的確定是否發(fā)生了內存泄漏逾冬。