谈谈jvm的调优思路
目录
1、G1回收器
2、常用的回收器分类
1、cms
2、G1、Hotspot
3、ZGC
4、设置
3、常见的调优策略
3.1、设定大小
1、堆的大小
2、Region的大小
3、年轻代大小调整
3.2、设置最大停顿时间
3.3、设置标记和回收线程
3.4、并发周期触发阈值
背景
正常情况下,都轮不到我们去调优,当jvm出现GC问题的时候,光通过修改参数,很难从根本上解决程序的问题。
由于后续他人不好维护,且当前调整的jvm参数只适用于某段时刻程序的流量性能,因此不可扩展。
因此,实际开发过程中,项目启动的时候,可以通过GC的回收机制、回收器的参数来进行规避。
更多GC回收,可参考:Java对象的内存布局及GC回收年龄的研究-CSDN博客
1、G1回收器
最早出现在jdk7,在java17中默认,G1回收器,堆内存会被划分为Eden、suvivor、old区、Humongous区(存放大对象)。
如下图所示:
在每个region区可分为内存为2的幂等。
堆内存被划分为不同的region区,每个region区大小是相等的。如果一个对象的大小占比超过region区的50%,则会被默认放到H区,后续也可以在H区方便回收对象。
2、常用的回收器分类
关于更多回收器的介绍,可参考:关于对JVM的知识整理_谈谈你对jvm的理解-CSDN博客
1、cms
jdk7,jdk8默认的,jdk14已经不支持。
2、G1、Hotspot
jdk8-17默认的回收器。
3、ZGC
jdk17出来,jdk21成为默认的回收器。
4、设置
启动jvm的时候,可以通过以下参数,指定jvm。
-XX:+UseCMSGC
-XX:+UseG1GC
3、常见的调优策略
3.1、设定大小
1、堆的大小
一般将堆的大小固定,通过参数:
-Xms -2048M -XMx -2048M 固定为大小2G
2、Region的大小
region的大小都是2的幂次,从1M->32M。
在heap比较小的时候,可以将region设定1m,2m,反之设置较大。
-XX:G1heapRegionSize=4M
选择依据:
-
默认值:堆大小/2048(最小1MB)
-
大对象(>50%Region大小)会直接进入老年代
-
超大对象(>整个Region)会分配在Humongous区域
3、年轻代大小调整
-XX:G1NewSizePercent=10 //年轻代最小占比
-XX:G1MaxNewSizePercent=30 //年轻代最大占比
-
增大年轻代可减少GC频率但增加单次停顿时间
-
观察
Young GC
时间调整至占整体停顿目标的1/3左右
3.2、设置最大停顿时间
G1的停顿预测模型,默认停顿时间为200ms,如果对于延迟较低的场景,可以通过设置MaxGCpauseMills来进行设置停顿时间。
-XX:MaxGCPauseMills=100
-
设置过低会导致GC更频繁
-
设置过高可能导致单次GC停顿时间过长
3.3、设置标记和回收线程
G1在标记和回收阶段,都属于多线程的操作。
-XX:ParalleGCThreads=8 //并行回收线程数为8(默认cpu核心数)
-XX: ConGCThreads = 8/4 //并行标记线程数为2
3.4、并发周期触发阈值
-XX:InitiatingHeapOccupancyPercent=45 # 默认45%
-
老年代占用达到该比例时启动并发标记周期
-
过早触发(值设高)会导致Full GC风险
-
过晚触发(值设低)会增加并发标记负担
完整的命令如下
java -Xms4G -Xmx4G \-XX:+UseG1GC \-XX:MaxGCPauseMillis=200 \-XX:G1HeapRegionSize=4M \-jar app.jar
总结
调整JVM的堆内存可以帮助避免内存溢出,提高垃圾回收的效率。合适的垃圾回收器能够提高应用的响应速度和吞吐量。
在实际操作中,建议逐步调整参数,并结合性能监控工具来评估调优效果。