“要宣布一個物件死亡至少要經歷兩次標記程序:如果通過可達性分析沒有與GC Roots相連接的參考鏈,會被第一次標記和進行一次篩選。篩選條件是此 物件是否有執行finalize()方法,當物件沒有覆寫finalize()方法,或者finalize()方法已經被虛擬機呼叫過。虛擬機將這兩種情況都視為“沒有必要執行”。
如果一個物件有必要執行finalize()方法,會被放在F-Queue佇列,并在稍后一個由虛擬機自己建立的、低優先級的Finalizer執行緒去執行它,虛擬機會觸 發這個方法,但是不會等它執行完,否則如果一個物件在finalize()方法中執行緩慢,那么記憶體回收系統會崩潰。finalize()方法是物件最后一次逃脫死亡機 會。稍后GC將對F-Queue中的物件進行第二次小規模標記,如果物件在第二次標記前沒能拯救自己就要被回收。拯救辦法是只要與參考鏈上任何一個物件建 立關聯即可。”
上面的內容來自書籍,如果按照上述,那么當物件的finalize()方法沒有必要執行,那不是只標記一次就可以嗎?
uj5u.com熱心網友回復:
兩次中的第二次其實是為了再做一些確認,防止回收的時候,又被參考了等uj5u.com熱心網友回復:
可是不是說第二次進行帥選的是小規模標記嗎,是在用戶沒有重寫finalize()方法或者沒有呼叫過finalize()方法的物件才會做第二次標記。。。。。還是有點不太懂uj5u.com熱心網友回復:
樓主要細讀,是具有finalize()的物件并且沒有執行finalize()方法的才會被放入F-Queue中并進行第二次標記,至于哪些沒有finalize()方法或者已經執行完這個方法還是需要被回收的只標記一次就可以回收了。uj5u.com熱心網友回復:
我就是細讀了,,才覺得書上的矛盾啊,他的第一句話就說了:GC前物件要至少進行兩次標記,而我從它下述的話中,覺得是一次即可的額,就是和你說的一樣,但是網上的筆記也是說至少兩次,矛盾啊uj5u.com熱心網友回復:
樓主要跟前面的那句話連在一起看哈,"即使在可達性分析演算法中不可達的物件,也并非是“非死不可”的,這時候它們暫時處于“緩刑”階段,要真正宣告一個物件死亡",人的前提就是這個死緩的物件要經歷兩次標記。
uj5u.com熱心網友回復:
在Java中每個物件都有一個唯一的“計數”,用來標記其被參考的次數:如果被變數參考則加一,否則減一;如果為0就表明該變數要被GC回收了uj5u.com熱心網友回復:
瞎扯。。。。
uj5u.com熱心網友回復:
沒工夫和你閑扯,你說別人總得有依據吧!
uj5u.com熱心網友回復:
我也是覺著很矛盾,要是死緩的物件沒有覆寫finalize()方法的話,那是不是就標記一次就被回收了。樓主有理清嗎?求教~~uj5u.com熱心網友回復:
在Java中每個物件都有一個唯一的“計數”,用來標記其被參考的次數:如果被變數參考則加一,否則減一;如果為0就表明該變數要被GC回收了
瞎扯。。。。
沒工夫和你閑扯,你說別人總得有依據吧!
class A{
public Object o;
}
A a1 = new A();
A a2 = new A();
a1.o = a2;
a2.o = a1;
參考計數怎么給我回收了
uj5u.com熱心網友回復:
首先你要明確,GC有很多種的。其中『參考計數』是一種古老的JavaGC機制,但是像你說的,在處理『回圈參考』的問題,于是現在基本上都采用『可達性GC機制』了。都是對的,只是他們各自適用于不同的問題范圍罷了。uj5u.com熱心網友回復:
如果物件沒有必要執行finalize()方法的話,標記一次就回收了uj5u.com熱心網友回復:
我也感覺此處有矛盾。。uj5u.com熱心網友回復:
個人的理解,至少兩次標記程序:1)第一次大標記:如果沒有覆寫finalize()方法,就標記,等待第二次大標記,如果覆寫了,就進入F-Queue里面,并進行小規模標記
2)第二次大標記:F-Queue小規模標記完成后,對所有滿足條件的(包括沒有覆寫finalize()方法的和執行過finalize()的)物件加入“即將回收”的集合,并把第二次小規模標記的物件進行移除“即將回收”的集合的操作
- 至于“第二次小規模標記”是發生在第一次大標記和第二次大標記之間,其中的第二次是相對于第一次大標記,算不上是第二次標記,其實也是作者語意上的表述方式啦
- 為何沒有覆寫finalize()方法的物件不再第一次大標記之后就立即釋放,就是1樓說的那樣,再次確認,順便等待F-Queue的小規模標記以后再清理
uj5u.com熱心網友回復:
我也是剛剛看到這里,有點疑惑上網搜到了這個帖子。樓主,我說一下我的理解,你的分析沒錯,如果一個類沒有重寫finalize方法,貌似好像只需要標記一次就可以了;如果重寫了finalize方法那么它可能在finalize方法內“拯救自己”。但是,如果這個“自我拯救”類含有其他沒有重寫finalize方法類的應用的時候會怎么樣呢?這樣只標記一次就清除的想法還是有些問題的。
比如下面代碼:
public class FinalizeEscapeGC {
class A {};
private static FinalizeEscapeGC SAVE_HOOK = null;
private A a = new A();
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();
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if ( SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no, i'm dead!");
}
}
}
類FinalizeEscapeGC重寫了finalize方法,類A沒有重寫finalize方法。當執行SAVE_HOOK = null后,這兩個物件都不可達了,如果對類A的物件只標記一次就清除的話,那么類FinalizeEscapeGC在finalize方法“自我拯救”后的屬性a就被清除了,就不在是原來的那個FinalizeEscapeGC了。
uj5u.com熱心網友回復:
有一個問題:和 F-Queue 佇列里面的物件保持連接的是屬于可觸及的還是不可觸及的呢?如果是可觸及的,樓上的分析就不對。可觸及不會被清除,屬性a 就會一直存在。。(關于這個問題沒百度到,可能有點傻逼,才開始學JVM)轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/60322.html
標籤:Java相關
