Java學習筆記 (三十) finalize()方法

可達性分析算法中不可達的對象,並不是一定要回收的。真正判定一個不可達對象要回收,至少要經歷兩次標記過程。

第一次標記

如果對象在進行可達性分析之後發現沒有與 GC Roots 相連接的引用鏈,那它將會被第一次標記並且進行一次篩選。
篩選的條件是此對象是否需要執行 finalize() 方法。當對象沒有覆寫 finalize() 方法,或者 finalize() 方法已經被虛擬機調用過,這兩種情況都是不需要執行 finalize() 方法。
如果對象被判定爲需要執行 finalize() 方法,這個對象就會被放在一個叫做 F-Queue 的隊列之中,並在稍後由一個虛擬機自動建立的、低優先級的 Finalizer 線程去執行它。這裏的執行是指虛擬機會觸發這個方法,但不一定會等待它運行結束。這是因爲如果一個對象在 finalize() 方法中執行緩慢,或者發生死循環,將可能導致 F-Queue 隊列中其他對象永久處於等待,甚至導致整個內存回收系統崩潰。

第二次標記

finalize() 方法是對象拯救自己的最後一次機會。
GC 會對 F-Queue 中的對象進行第二次標記,如果對象在finalize()方法中 將自己與引用鏈的任何一個對象建立關聯, 那麼在第二次標記時它將會被移出 即將回收的集合。否則將會被回收。

示例

如下,對象第一次成功拯救自己,第二次只能死亡。。。。

package finalize;

public class FinalizeEscapeGC {

    static FinalizeEscapeGC finalizeEscapeGC=null;



    @Override
    protected void finalize() throws Throwable {
        System.out.println("拯救自己...........................");
        //將自己與引用鏈關聯起來
        finalizeEscapeGC=this;
    }

    public void isLive(String name){
        System.out.println(name+": 對象還活着.........");
    }

    public static void main(String []args) throws Exception{
        finalizeEscapeGC=new FinalizeEscapeGC();

        //讓對象可以被回收
        finalizeEscapeGC=null;

        System.gc();

        //finalize 方法優先級很低,所以暫停 0.5 秒以等待它
        Thread.sleep(500);

        if (finalizeEscapeGC==null){
            System.out.println("第一次 對象死了。。。。。。。。。");
        }else {
            finalizeEscapeGC.isLive("第一次 ");
        }


        //讓對象可以被回收
        finalizeEscapeGC=null;

        System.gc();

        //finalize 方法優先級很低,所以暫停 0.5 秒以等待它
        Thread.sleep(500);

        if (finalizeEscapeGC==null){
            System.out.println("第二次 對象死了。。。。。。。。。");
        }else {
            finalizeEscapeGC.isLive("第二次 ");
        }


    }

}

執行結果輸出如下:
在這裏插入圖片描述
可以看出,GC之後,finalize() 方法觸發,與引用鏈關聯,成功執行自己,第二次卻沒有觸發 finalize() 方法。
這是因爲任何一個對象的 finalize() 方法都只會被系統自動調用一次,第二次垃圾回收時 finalize() 方法將不會執行。

參考資料

學習摘抄於深入理解Java虛擬機

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章