深入理解java虛擬機-生存或者死亡

即使在可達性分析算法中不可達的對象,也并非是“非死不可”的,這時候它們暫時處于“緩刑”階段,要真正宣告一個對象死亡,至少要經(jīng)歷兩次標記過程:

  1. 如果對象在進行可達性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈,那它將會被第一次標記并且進行一次篩選,篩選的條件是此對象是否有必要執(zhí)行finalize()方法。
  2. 當對象沒有覆蓋finalize()方法,或者finalize()方法已經(jīng)被虛擬機調(diào)用過,虛擬機將這兩種情況都視為“沒有必要執(zhí)行”。

如果這個對象被判定為有必要執(zhí)行finalize()方法,那么這個對象將會放置在一個叫做F-Queue的隊列之中。稍后由一個由虛擬機自動建立的、低優(yōu)先級的Finalizer線程去執(zhí)行它。

這里所謂的“執(zhí)行”是指虛擬機會觸發(fā)這個方法,但并不承諾會等待它運行結(jié)束,這樣做的原因是,如果一個對象在finalize()方法中執(zhí)行緩慢,或者發(fā)生了死循環(huán)(更極端的情況),將很可能會導致F-Queue隊列中其他對象永久處于等待,甚至導致整個內(nèi)存回收系統(tǒng)崩潰。

finalize()方法是對象逃脫死亡命運的最后一次機會,稍后GC將對F-Queue中的對象進行第二次小規(guī)模的標記,如果對象要在finalize()中成功拯救自己——只要重新與引用鏈上的任何一個對象建立關(guān)聯(lián)即可,譬如把自己(this關(guān)鍵字)賦值給某個類變量或者對象的成員變量,那在第二次標記時它將被移除出“即將回收”的集合;如果對象這時候還沒有逃脫,那基本上它就真的被回收了。從代碼清單3-2中我們可以看到一個對象的finalize()被執(zhí)行,但是它仍然可以存活。

此代碼演示了兩點:
1.對象可以在被GC時自我拯救。
2.這種自救的機會只有一次,因為一個對象的finalize()方法最多只會被系統(tǒng)自動調(diào)用一次

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 mehtod executed!");
            FinalizeEscapeGC.SAVE_HOOK = this;
    }
    public static void main(String[] args) throws Throwable {
            SAVE_HOOK = new FinalizeEscapeGC();
            //對象第一次成功拯救自己
            SAVE_HOOK = null;
            System.gc();
            //因為finalize方法優(yōu)先級很低,所以暫停0.5秒以等待它
            Thread.sleep(500);
            if (SAVE_HOOK != null) {
                    SAVE_HOOK.isAlive();
            } else {
                    System.out.println("no, i am dead :(");
            }
            //下面這段代碼與上面的完全相同,但是這次自救卻失敗了
            SAVE_HOOK = null;
            System.gc();
            //因為finalize方法優(yōu)先級很低,所以暫停0.5秒以等待它
            Thread.sleep(500);
            if (SAVE_HOOK != null) {
                    SAVE_HOOK.isAlive();
            } else {
                    System.out.println("no, i am dead :(");
            }
    }
}

運行結(jié)果:

finalize mehtod executed!
yes, i am still alive :)
no, i am dead :(

結(jié)果可以看出,SAVE_HOOK對象的finalize()方法確實被GC收集器觸發(fā)過,并且在被收集前成功逃脫了。

另外一個值得注意的地方是,代碼中有兩段完全一樣的代碼片段,執(zhí)行結(jié)果卻是一次逃脫成功,一次失敗.

這是因為任何一個對象的finalize()方法都只會被系統(tǒng)自動調(diào)用一次,如果對象面臨下一次回收,它的finalize()方法不會被再次執(zhí)行,因此第二段代碼的自救行動失敗了。

首先,大致描述一下finalize流程:當對象變成(GC Roots)不可達時,GC會判斷該對象是否覆蓋了finalize方法,若未覆蓋,則直接將其回收。否則,若對象未執(zhí)行過finalize方法,將其放入F-Queue隊列,由一低優(yōu)先級線程執(zhí)行該隊列中對象的finalize方法。執(zhí)行finalize方法完畢后,GC會再次判斷該對象是否可達,若不可達,則進行回收,否則,對象“復活”。

ps :不是很有用,當做記錄吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容