一又碌、Finalize方法的過(guò)程
一個(gè)對(duì)象真正宣告死亡瓢颅,至少要經(jīng)歷兩次標(biāo)記過(guò)程:如果對(duì)象在進(jìn)行可達(dá)性分析之后發(fā)現(xiàn)沒(méi)有與GC Roots相連接的引用鏈,那它將被第一次標(biāo)記并且進(jìn)行一次篩選垫卤。篩選的條件是此對(duì)象是否有必要執(zhí)行finalize()方法社牲。
當(dāng)遇到以下兩種情況時(shí),虛擬機(jī)將視為“沒(méi)有必要執(zhí)行”:
1.對(duì)象是否覆蓋finalize()方法
2.finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過(guò)
如果這個(gè)對(duì)象被判定為有必要執(zhí)行finalize()方法纺铭,那么這個(gè)對(duì)象將會(huì)被放置在一個(gè)F-Queue的隊(duì)列中寇钉,并在稍后由一個(gè)由虛擬機(jī)自動(dòng)建立的、低優(yōu)先級(jí)的Finalizer線(xiàn)程執(zhí)行舶赔。
注:這里的“執(zhí)行”指的是虛擬機(jī)有機(jī)會(huì)觸發(fā)這個(gè)方法扫倡,但并不承諾會(huì)等待它運(yùn)行結(jié)束。因?yàn)橐粋€(gè)對(duì)象在finalize()方法中執(zhí)行是非常緩慢的竟纳,甚至有可能會(huì)發(fā)生死循環(huán)撵溃,將會(huì)導(dǎo)致F-Queue隊(duì)列中其他對(duì)象永久處于等待,甚至導(dǎo)致整個(gè)內(nèi)存回收系統(tǒng)崩潰锥累。
finalize()方法是對(duì)象逃脫死亡命運(yùn)的最后一次機(jī)會(huì)缘挑,稍后GC將對(duì)F-Queue中的對(duì)象進(jìn)行第二次小規(guī)模的標(biāo)記,如果對(duì)象在finalize()方法中拯救自己(重新與引用鏈上任何一個(gè)對(duì)象建立關(guān)聯(lián))桶略,那么在第二次標(biāo)記時(shí)它將被移除“即將回收”的集合语淘,如果對(duì)象這時(shí)候還沒(méi)有逃脫,那基本上就真的被回收了~~~(gg
二际歼、一次對(duì)象的自我拯救代碼清單
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println("yes,I am still alive :)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws Throwable {
SAVE_HOOK = new FinalizeEscapeGC();
//對(duì)象第一次成功拯救自己
SAVE_HOOK = null;
System.gc();
//因?yàn)閒inalize方法優(yōu)先級(jí)很低惶翻,所以暫停0.5s等待
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no,I am dead :(");
}
//第二次拯救失敗
SAVE_HOOK = null;
System.gc();
//因?yàn)閒inalize方法優(yōu)先級(jí)很低,所以暫停0.5s等待
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no,I am dead :(");
}
}}
運(yùn)行結(jié)果:
finalize method executed!
yes,I am still alive :)
no,I am dead :(
從代碼清單中可知鹅心,SAVE_HOOK對(duì)象的finalize()方法確實(shí)被GC收集器觸發(fā)過(guò)吕粗,并且在被收集前成功逃脫了。
另外旭愧,在完全一樣的兩端代碼片段里颅筋,第二次的執(zhí)行結(jié)果確實(shí)逃脫失敗了虐秋。這是因?yàn)槿魏我粋€(gè)對(duì)象的finalize()方法都只會(huì)被系統(tǒng)自動(dòng)調(diào)用一次,如果對(duì)象面臨下一次回收垃沦,它的finalize()方法就不會(huì)被再次執(zhí)行客给。
最后,在JVM中并不鼓勵(lì)使用finalize()對(duì)象來(lái)拯救對(duì)象肢簿。因此它的運(yùn)行代碼非常高昂而且不確定性大靶剑。finalize()方法能做的工作,使用try-finally或者其他方式都可以做的更好更及時(shí)池充。