JVM之Survivor區使用率以及對象晉升年齡

本文基於jdk1.8

Survivor區中From和To區域默認使用率都是50%,在new對象過程中,如果eden區不夠對象會進入Survivor區,如果Survivor區容量不夠,對象會直接分配進入年老代。

Survivor區中存在的對象,jvm會記錄其晉升年齡,並且會自動計算晉升年齡閾值,如果對象晉升年齡超過閾值,則會進入年老代。

以下兩個參數可以控制Survivor區使用率,以及晉升年齡最大閾值:

#Survivor區使用率
-XX::TargetSurvivorRatio 
#晉升年齡最大值
-XX:MaxTenuringThreshold 

下面我們運行一段代碼來演示一下,我們打算分配1024的空間給jvm,並且關閉其自動調整eden和Survivor大小的策略,保持這兩個區的空間分配穩定。

運行程序後,通過jmap查看堆空間,FROM和TO space大概是10MB,所以我們代碼每次分配7MB的空間,用來測試大於50%但是小於FROM SPACE的場景;這樣可以觀察到對象是否直接進入年老代。

#準備代碼
private static List<Object> list = Lists.newArrayList();
public void gcTest() throws Exception {
	list.add(new byte[1024 * 1024 * 7]);
	LOG.info("初始化對象...");
}

#運行程序,關閉動態調整策略(-XX:-UseAdaptiveSizePolicy),Survivor區使用率默認
nohup java -Xms256M -Xmx256M -XX:-UseAdaptiveSizePolicy -Xloggc:gc.log -jar microservice-web-1.0-SNAPSHOT.jar &

多次調用,每次調用後觀察堆空間使用;在第9次調用時候觸發了GC,由於新申請的7MB大於Survivor區最大使用率(10MB*50%=5MB),所以都進入了年老代。

#再次啓動,Survivor區使用率設置爲80%(-XX:TargetSurvivorRatio=80)
nohup java -Xms256M -Xmx256M -XX:-UseAdaptiveSizePolicy -XX:TargetSurvivorRatio=80 -jar microservice-web-1.0-SNAPSHOT.jar &

多次調用,每次調用後觀察堆空間使用;在第9次調用時觸發了GC,list由於存儲了前8個對象直接進入年老代; From space總共10MB,使用率80%=8MB,第九次申請了7MB的堆空間,所以對象進入了FROM區。

優化場景

實際使用過程中,如果發現FULL GC頻率過高,可以適當Survivor區使用率以及對象晉升閾值,以減少對象進入年老代頻率,從而減少FULL GC次數。

同時如果需要從GC日誌中跟蹤對象晉升年齡,可以設定GC日誌參數:XX:+PrintTenuringDistribution;參考另一篇《GC日誌分析》:https://my.oschina.net/u/3457546/blog/4734173。

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