https://www.zhihu.com/question/62953438?from=profile_question_card
父類特性
整體邏輯蚯瞧,JVM將待回收對象對應(yīng)的Reference對象放入pending列表,由ReferenceHandler將pending列表中的對象取出放入ReferenceQueue,以此作為一個通知機(jī)制忽舟。
Reference next;
Reference類型的對象類似鏈表的節(jié)點(diǎn)淮阐,每個Reference類型的對象持有下一個Reference類型的對象的引用叮阅,這樣組成了單向鏈表(ReferenceQueue實(shí)際節(jié)點(diǎn))。
private static Reference<Object> pending = null;
static字段泣特,整個JVM只有唯一的一個浩姥。JVM的垃圾回收器會將所有被標(biāo)記對象對應(yīng)的Reference類型的對象添加到這里,組成Reference類型的對象的單向鏈表状您,這一步是JVM做的勒叠。
private static class ReferenceHandler extends Thread;
內(nèi)部類線程镀裤,在Reference的static代碼塊創(chuàng)建,JVM全局唯一缴饭。
public void run() {
while (true) {
tryHandlePending(true);
}
}
### static boolean tryHandlePending(boolean waitForNotify)
不斷從pending上的Reference類型的對象的單向鏈表上取出Reference類型對象,然后將改Reference類型對象放入Reference類型的對象自帶的ReferenceQueue中骆莹。
如果Reference類型對象是Cleaner颗搂,調(diào)用Cleaner的clean()方法。
子類
SoftReference
WeakReference
-
WeakHashMap(應(yīng)用)
通過查詢queue中的數(shù)據(jù)幕垦,判斷是否有對象被回收丢氢,被回收則刪除map中對應(yīng)的key。
-
ThreadLocalMap(應(yīng)用)
構(gòu)造WeakReference對象時未傳入queue先改,通過不斷調(diào)用get()方法判斷是否為null來確定對象是否被回收疚察。
PhantomReference
Finalizer vs. Cleaner
因?yàn)镕inalizer也是一種Reference,所以前邊Reference的處理邏輯是和Weak, Soft reference的邏輯十分相似的仇奶。
而且Finalizer和Cleaner的作用也十分相似貌嫡,但有一個巨大的不同在于,finalize方法里可以使object 復(fù)活该溯,而 Cleaner 的 clean 方法中不能使得對象復(fù)活岛抄。
這是因?yàn)?finalize 中,可以通過 this 指針訪問到 object 對象狈茉,例如:
public void finalize() {
Other.ref = this;
}
這樣的話夫椭,一個本來應(yīng)該被回收的對象又在finalize之后復(fù)活了。但是Cleaner為什么不行呢氯庆?因?yàn)樗幕愂且粋€PhantomReference蹭秋,這個“鬼引用”的 get 方法是這樣的:
public class PhantomReference<T> extends Reference<T> {
public T get() {
return null;
}
// 其它代碼略
}
永遠(yuǎn)返回null,也就是說對于Cleaner堤撵,創(chuàng)建了以后仁讨,就再也不能訪問它的referent了。
Cleaner(子類)
DirectByteBuffer(應(yīng)用)
-
private static Cleaner first = null;
Cleaner.create方法會將Cleaner對象加到一個雙向鏈表中去粒督,這樣做是為了保證在referent被回收之前這些Cleaner都是存活的陪竿。
FinalReference
FinalReference僅僅繼承了Reference,沒有做其他的邏輯屠橄,只是將訪問權(quán)限聲明為package族跛,所以我們不能夠直接使用它。
-
Finalizer(子類)
只要類覆寫了Object 上的finalize方法锐墙,方法體非空礁哄。那么這個類的實(shí)例都會被Finalizer引用類型引用。這個工作是由虛擬機(jī)完成的溪北,對于我們來說是透明的桐绒。
覆蓋了finalize方法的對象至少需要兩次GC才可能被回收夺脾。第一次GC把覆蓋了finalize方法的對象對應(yīng)的Finalizer reference加入referenceQueue等待FinalizerThread來執(zhí)行finalize方法。第二次GC才有可能釋放finalizee對象本身茉继,前提是FinalizerThread已經(jīng)執(zhí)行完finalize方法了咧叭,并把Finalizer reference從Finalizer靜態(tài)unfinalized鏈表中剔除,因?yàn)檫@個鏈表和Finalizer reference對finalizee構(gòu)成的是一個強(qiáng)引用烁竭。
- private static ReferenceQueue queue = new ReferenceQueue();
- private static Finalizer unfinalized;
維護(hù)了一個未執(zhí)行finalize方法的reference列表菲茬。維護(hù)靜態(tài)字段unfinalized的目的是為了一直保持對未未執(zhí)行finalize方法的reference的強(qiáng)引用,防止被gc回收掉派撕。
- private static class FinalizerThread extends Thread;
Finalizer靜態(tài)代碼塊里啟動了一個deamon線程 FinalizerThread婉弹,F(xiàn)inalizerThread run方法不斷的從queue中去取Finalizer類型的reference,然后調(diào)用Finalizer的runFinalizer方法终吼,該方法最后執(zhí)行了referent所重寫的finalize方法镀赌。finalize方法執(zhí)行之后移除unfinalized列表。