預備知識
- Java的Gc只負責內存的清理,其它方面的清理要程序員手工操作
- 調用Gc并不能保證Gc一定會執(zhí)行,因為GC的線程優(yōu)先級比較低,所以在測試的時候調用完GC一般使當前線程睡眠以便GC線程的執(zhí)行。
- 用戶自己調用finalize函數并不會影響到清理徽鼎,和調用一個正常的方法一樣,沒有什么特別的影響
- jvm保證一個對象占用的內存回收之前弹惦,如果這個對象的類實現(xiàn)了finalize方法否淤,一定會執(zhí)行且僅執(zhí)行一次,至于如何保證的會在下面講到
- 對象的finalize鏈需要手工構造棠隐,也就是如果重寫finalize函數需要手動調用
super.finalize()
對象的銷毀過程
沒有重寫finalize方法
- 剛創(chuàng)建的對象狀態(tài)是reachable石抡,如果對象變成不可達,GC會直接將對象銷毀
重寫了finalize方法
- 剛創(chuàng)建:reachable + unfinalized狀態(tài)助泽,意思是:該對象可達啰扛,而且該對象的finalize函數還沒有被調用,并且沒有準備被調用嗡贺,因為該對象可達GC不會試圖去銷毀該對象隐解。
- 對象的引用沒有了,現(xiàn)在是不可達狀態(tài)暑刃,但是因為其重寫了finalize函數厢漩,所以jvm會將該對象放到F-queue中,該隊列中的對象狀態(tài)都變成:F-reachable + finalizable岩臣,意思是:該對象通過F-queue可達而且準備被調用finalize函數。
- 在任何時候宵膨,如果F-queue隊列非空架谎,GC的一個線程都會從該隊列中取出一個對象,將其狀態(tài)標記為:unreachable + finablized辟躏,并執(zhí)行它的finalize函數谷扣, 意思是:該對象現(xiàn)在不可達,而且已經執(zhí)行過finalize函數,不能再次被放到F-queue隊列中会涎,也就保證了finalize只會被執(zhí)行一次裹匙。
- 如果F-queue中的一個對象在其finalize函數中“復活了自己”---將自己的引用又賦值給了一個變量,這個時候這個對象就再次變成了reachable末秃,但是他的finalize函數仍然不會被再次執(zhí)行概页,也就是說它現(xiàn)在的狀態(tài)類似于一個沒有覆蓋finalize函數的對象,如果再次變得不可達练慕,會直接被GC銷毀惰匙。
- 下面演示一個對象在finalize函數中復活自己的例子:
public class Main{
static Main HOOK;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize function is called");
HOOK=this;
}
public static void main(String[] args) throws InterruptedException {
HOOK = new Main();
HOOK=null;
System.gc();
Thread.sleep(3000);
if(HOOK==null){
System.out.println("object is dead");
}else {
System.out.println("object is alive");
}
HOOK=null;
System.gc();
Thread.sleep(3000);
if(HOOK==null){
System.out.println("object is dead");
}else {
System.out.println("object is alive");
}
}
}
finalize function is called
object is alive
object is dead
- GC第一次執(zhí)行的時候,調用了finalize函數铃将,通過將this引用賦值給另一個變量项鬼,將對象復活,所以對象仍然是存活的劲阎,但是第二次就不會在調用finalize函數绘盟,所以對象被銷毀。
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者