2011-06-07 62 views
3

這個問題是continuation of this one,但要求更具體的情況。最終的成員變量可以使GC更好嗎?

比方說我們有以下類:

public class Person { 
    private Foot left, right; 

    public Person(Foot left, Foot right) { 
     this.left = left; 
     this.right = right; 
    } 
} 

我在想,如果下面的類將能夠從GC的角度優化的,如果我們把它分爲以下幾個:

public class Person { 
    private final Foot left, right; 

    public Person(Foot left, Foot right) { 
     this.left = left; 
     this.right = right; 
    } 
} 

如果我在看這個類,我可以立刻知道左右變量永遠不能設置爲null。這意味着只有當GC需要收集這個類的左側和右側對象(並減少對它的引用)時,纔會對父類Person的引用達到零。它也應該意味着它可以在收集左腳和右腳的同時收集人;也導致更少的運行和加速。

因此,在這個例子中,是否標記私有成員變量最終意味着代碼將導致垃圾收集中的一小部分加速(或者它可能被用作加速點)?

+0

在前面的問題的答案似乎很明確地說出了答案爲「否」的任何有用的信息 - 有這些問題的答案的某些部分那不清楚?否則,這個問題聽起來幾乎完全一樣 – 2011-06-07 02:26:43

回答

7

由於Java GC不使用引用計數(*),賦值給字段不會觸發任何垃圾收集器工作或引用計數調整。所以答案是,宣佈一個字段爲final對垃圾回收器性能沒有影響。 (收集的跟蹤階段必須檢查該字段是否它是不是final

可以想象的是,聲明一個領域是final可以幫助JIT編譯器的數據流分析和內存優化獲取。然而,如果你打算這樣做,那是爲了正確性的原因(即爲了在併發環境下安全構建)或者爲了文體上的原因(也就是爲了使得代碼更容易理解和維護)

(*沒有主流的Java實現依靠引用計數來實現內存管理。理論上可能有人可能實現了一個使用引用計數的JVM,但傳統觀點認爲引用計數的效率非常低下......更不用提併發,收集週期等問題了。)

+0

_do它爲了文體上的原因_這聽起來不對。設置最終字段(常規方式,無反射)是內存屏障,因此運行時(JVM)'保證對象被正確構造,並且最終字段在構造函數完成之前正確地構造。 (保證內存可見性)。這在多線程程序中非常重要。 – 2011-06-07 02:59:47

+0

這個反應非常好。 TIL表示沒有Java GC使用引用計數。雖然Op De Cirkel正確地說明最終字段對確保不可變對象有用。而且我知道設置字段不會觸發垃圾回收,但當代碼庫中其他位置的person對象設置爲null並標記爲垃圾回收時,怎麼辦?這是否意味着你也有可能爲了收穫而標記雙腳? – 2011-06-07 03:07:14

+1

@Robert Massaioli - 沒有「垃圾收集標記」。唯一的標記是不標記爲垃圾收集。 AFAIK,這裏沒有優化的機會。 – 2011-06-07 03:15:08

0

Java垃圾回收不起作用通過參考計數。它通過檢查物體的可達性來工作。

+0

_垃圾收集不檢查對象的reference_工作怎麼可能呢? – 2011-06-07 02:43:42

+0

@Stephen C @Op De Cirkel謝謝,重新編寫。 – EJP 2011-06-07 04:56:34

1

的唯一原因, GC優化是不可能 ,是因爲JVM規範確實允許改變final場。
final字段在對象構建過程中具有特殊語義,這對構造過程正確工作有關Java內存模型很重要。但是你可以打破規則並使用反思來改變它。在這種情況下,你不能依靠final場(關於Java內存模型

罷工的語義:對不起球員,我不知道我在說什麼。最終與GC無關。即使最後是不能改變的一切,GC不能得到這個事實

+0

這是假設性的。它假設會有一些基於'final'字段的優化......這是不正確的。 – 2011-06-07 03:01:07

相關問題