從實際案例聊聊Java應用的GC優化
關于上文中提到晉升年齡門檻值為2,很多同學有疑問,為什麼設定了MaxTenuringThreshold=15,對象仍然僅經曆2次Minor GC,就晉升到老年代?這裡涉及到“動态年齡計算”的概念。
動态年齡計算:Hotspot周遊所有對象時,按照年齡從小到大對其所占用的大小進行累積,當累積的某個年齡大小超過了survivor區的一半時,取這個年齡和MaxTenuringThreshold中更小的一個值,作為新的晉升年齡門檻值。在本案例中,調優前:Survivor區 = 64M,desired survivor = 32M,此時Survivor區中age<=2的對象累計大小為41M,41M大于32M,是以晉升年齡門檻值被設定為2,下次Minor GC時将年齡超過2的對象被晉升到老年代。
JVM引入動态年齡計算,主要基于如下兩點考慮:
如果固定按照MaxTenuringThreshold設定的門檻值作為晉升條件: a)MaxTenuringThreshold設定的過大,原本應該晉升的對象一直停留在Survivor區,直到Survivor區溢出,一旦溢出發生,Eden+Svuvivor中對象将不再依據年齡全部提升到老年代,這樣對象老化的機制就失效了。 b)MaxTenuringThreshold設定的過小,“過早晉升”即對象不能在新生代充分被回收,大量短期對象被晉升到老年代,老年代空間迅速增長,引起頻繁的Major GC。分代回收失去了意義,嚴重影響GC性能。
相同應用在不同時間的表現不同:特殊任務的執行或者流量成分的變化,都會導緻對象的生命周期分布發生波動,那麼固定的門檻值設定,因為無法動态适應變化,會造成和上面相同的問題。
總結來說,為了更好的适應不同程式的記憶體情況,虛拟機并不總是要求對象年齡必須達到Maxtenuringthreshhold再晉級老年代。