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。

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