JVM G1性能调优
G1简介和常用配置可参考:JVM G1垃圾回收器简介与常用配置
G1调优概要
G1整体上保持默认配置即可,最多配置一下 pause-time goal或堆内存大小(-Xmx
和-Xms
)。
不像其他的垃圾回收器,G1默认已经在最大吞吐和低时延之间做了平衡。但是,G1在堆中的增量式空间回收和pause-time控制机制给应用线程 和回收效率上都带来了负担。
如果需要大吞吐(非在线业务,如后台任务),可以适当调大期望最大停顿时间(-XX:MaxGCPauseMillis
) 或者调大堆空间。
如果需要低时延(在线业务),可以调小最大停顿时间。
不要配置-Xmn
,-XX:NewRatio
等参数,这些会限制年轻代空间大小,而年轻代是G1实现预期停顿时间的主要方式,将年轻代大小设置为一个固定值会导致G1的停顿时间控制失效。
G1性能调优
G1在大多数场景不需要要调优,针对需要调优的场景,本章给出一些性能诊断和调优指南。
为了定位性能瓶颈,可以配置参数-Xlog:gc*=debug
。
低时延调优
gc+cpu=info
日志会打印pause-time的耗时详情,如User=0.19s Sys=0.00s Real=0.01s
。
其中,User
表示进程执行用户态代码(核心之外)消耗的时间,Sys
表示进程在内核态消耗的时间,Real
表示程序从开始到结束所用的时间。 这里User
+ Sys
时间的和比 Real
时间要大,这主要是因为日志时间是从 JVM 中获得的,而这个 JVM 在多核的处理器上被配置了多个 GC 线程, 由于多个线程并行地执行 GC,因此整个 GC 工作被这些线程共享,最终导致 Real
< User
+ Sys
,如果是单线程的垃圾回收器,如Serial垃圾回收器,则 Real
= User
+ Sys
如果Sys
时间过大,可能的原因有:
VM向操作系统申请内存时导致的delay,可以将 -Xms 和 -Xmx 值设为一致, 避免内存的频繁分配。通过JVM的参数-Xmx和-Xms可以设置JVM的堆大小, 但是此时操作系统分配的只是虚拟内存,只有JVM真正要使用该内存时,才会被分配物理内存。 使用-XX:+AlwaysPreTouch
参数在服务启动时即分配物理内存给VM
特别是在Linux中, Transparent Huge Pages (THP) 特性会随机暂停进程,不仅仅在pause-time时, 可以参考对应的操作系统去关闭THP特性
写日志可能会线程暂停,日志线程会占用写磁盘的带宽。
如果Real
» User
+ Sys
则表示VM没有获得足够的CPU时间片,机器配置低了。
Young-Only Collection 耗时过长。一般来讲,年轻代垃圾回收耗时和年轻代空间大小成正比,主要原因是G1通过复制-整理方式 来聚合GC后的对象(即复制到Survivor区)。可以通过减小 -XX:G1NewSizePercent
和 -XX:G1MaxNewSizePercent
来限制年轻代占整个已使用堆内存的最小和最大百分比,以此来减小单次GC耗时。
Mixed Collection 耗时过长。Mixed Collection包含年轻代和老年代的Regions,可以配置gc+ergo+cset=trace
观察 年轻代和老年代在Mixed Collection过程中的耗时占用。如果是老年代GC耗时过长,可以做如下调整:
- 增大
-XX:G1MixedGCCountTarget=8
:最多8次混合垃圾回收, 设置标记周期完成后, 对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数 - 调整
XX:G1MixedGCLiveThresholdPercent=70
:默认值 : 65%, MixGC时, 年老代Region中存活对象百分比, 只有在此阈值下的Region才会被选入回收列表CSet (需开启-XX: +UnlockExperimentalVMOptions ) - 增大
-XX:G1HeapWastePercent=10
:默认值 : 10% , 堆浪费百分比, 当G1发现可被回收的空间小于10%时, 就不会再进行混合收集, 也就是会结束当前的混合收集周期
同时,可以调整-XX:GCPauseIntervalMillis
参数来控制两次GC的时间间隔
G1使用Remember Set(RS)记录跨Region的对象引用,如果RS扫描和更新时间长,可以适当减小Region大小,通过配置-XX:G1HeapRegionSize=4M
实现。 同时,G1会并发来更新RS,
VM有优化尝试减少并发RS更新来批量更新RS,如果批量更新的批次在GC前创建,则会导致RS pause-time变大,可以通过-XX:-ReduceInitialCardMarks
关闭该优化。
RS扫描时间高也可能是由于大量的RS压缩(remembered set coarsening)导致,coarsening可以减小RS空间,但会增加RS变更和获取的耗时。 该压缩默认开启,可以配置-XX:G1SummarizeRSetStatsPeriod
和gc+remset=trace
查看是否发生了coarsening,增大-XX:G1RSetRegionEntries
可以降低coarsening的数量。
同时,生产环境应避免开启RS详细日志。
大吞吐调优
一些后台任务场景更加重视吞吐而不是时延,可以通过一下配置优化吞吐性能:
- 增大
-XX:MaxGCPauseMillis
: 增大GC最大耗时 - 增大
-XX:G1MaxNewSizePercent
: 增大年轻代占已使用堆空间的百分比 - 减小并行工作:增大
-XX:G1RSetUpdatingPauseTimePercent
,关闭并行更新RS可配置-XX:-G1UseAdaptiveConcRefinement -XX:G1ConcRefinementGreenZone=2G -XX:G1ConcRefinementThreads=0
- 开启大内存也使用:
-XX:+UseLargePages
- 将
-Xms
和-Xmx
值设为一样,并配置-XX:+AlwaysPreTouch
堆空间调优
-XX:GCTimeRatio
表示GC外的耗时和GC耗时的比例,假设-XX:GCTimeRatio=19 ,则垃圾收集时间为1/(1+19),默认值为99,即1%时间用于垃圾收集