java虚拟机(十三)--GC调优思路
GC调优对我们开发人员来说,如果你想要技术方面一直发展下去,这部分内容的了解是必不可少的,jvm对于工作、面试来说都很重要,GC调优的问题
更是重中之重,因为是对你jvm学习内容的实践,知识只有应用实践出来才有意义,否则知识纸上谈兵。
首先,我们需要了解的内容,包括:
1、jvm内存结构:java虚拟(一)--java内存区域和常量池概念
2、垃圾收集算法:java虚拟机(五)--垃圾回收机制GC
3、常见的垃圾收集器:java虚拟机(六)--垃圾收集器和内存分配策略
4、GC日志分析:java虚拟机(十一)--GC日志分析 java虚拟机(十二)--可视化工具分析GC日志
5、jvm常见参数:java虚拟机(九)--常用jvm参数
PS:本文GC调优非生产环境,只是个人Linux系统对一个简单项目的启动调优,通过GC日志调整相关参数,学习GC调优的方法,最终在生产环境得到应用
网上有很多生产环境GC调优的案例,请自行参考
垃圾回收器的主要衡量标准:
1、吞吐量
2、最大停顿时间
GC调优步骤:
1、打印GC日志
2、根据日志获得关键性能指标
3、分析GC原因,调优JVM参数
Parallel GC调优:
官网建议:
1、除非确定,否则不要设置最大堆内存
2、优先设置吞吐量目标
3、如果吞吐量目标达不到,调大最大内存,不能让OS使用Swap,如果任然达不到,降低目标
4、如果吞吐量能达到,GC时间太长,设置停顿时间的目标
首先设置参数:
JAVA_OPTS="-XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_HOME/logs/ -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:$CATALINA_HOME/logs/gc.log"
-XX:+DisableExplicitGC:是指禁止代码中通过system.gc()主动调用GC
将生成的GC日志通过GCeasy分析,首先看到吞吐量为93.78%
发生12GC,2次Full GC,10次Minor GC,Minor GC和Full GC的时间如下:
GC发生的原因:
其中Ergonomics导致一次Full GC,耗时为130ms,时间最长
Metadata GC Threshold导致发生1次Full GC,一次Minor GC
Allocation Failure和GCLocker Initiated GC导致9次Minor GC
调优步骤如下:调优就是实验的过程
其中Ergonomics为jvm的自适应,根据CPU和内存情况自行调节jvm内存结构,但是也导致了一次Full GC
官方建议:除非很确定,否则不要设置最大堆内存,所以这里不调节堆内存
1、因为Metaspace GC Thread出现Full GC,所以这里选择调节-XX:MetaspaceSize=64M,因为最大使用了22.74M
吞吐量有了提高,GC次数降低,最大GC Pause为70ms,所以我们对于MetaspaceSize的调节是对的
2、对于一个测试项目来说,我们只是测试启动GC,95.94%的吞吐量,不够高,所以这里测试一下:
-XX:MaxGCPauseMillis=100 -XX:GCTimeRatio=99,最大GC时间位100ms,吞吐量为99%
发现为了提高吞吐量,吞吐量有了小幅度提升,但是GC时间却增长了很多
11次GC中有10次Minor GC,原因都是Allocation Failure
3、我们选择内存动态扩容增量参数,调节为30,我们查询直到,默认为20%
# jinfo -flag YoungGenerationSizeIncrement 25436 -XX:YoungGenerationSizeIncrement=20
调节发现,吞吐量为94.346%,所以这里这个参数不太适合
所以GC调优就是不断试验的过程,调优的次数多了,就有了经验,还有其他很多参数,都可以试验测试,查看起到的作用
PS:我这里测试的参数可能和你的项目以及环境不同,起到的作用可能不同,例如动态扩容参数,换个项目可能就会有好的作用
G1调优:jdk1.8一般采用G1
官网建议:
1、年轻代大小:
避免使用-Xmn、-XX:NewRatio等显式设置Young区大小,会覆盖暂定时间目标
2、暂停时间目标:
暂停时间不要太苛刻,吞吐量目标为90%,太严苛影响吞吐量
3、关于Mixed GC调优参数:
-XX:InitiatingHeapOccupancyPercent:
堆占有率达到这个数值则触发global concurrent marking,默认45%
-XX:G1HeapWastePercent:
在global concurrent marking结束之后,可以知道区中有多少空间要被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是
否达到这个参数,如果达到了,下次才会发生Mixed GC。
-XX:G1MixedGCLiveThresholdPercent:
Old区Region被回收的时候,存货对象的占比
-XX:G1MixedGCCountTarget:
-XX:G1OldSetRegionThresholdPercent:
调优步骤如下:
1、默认情况下
When you see to-space overflow or to-space exhausted messages in your logs, the G1 GC does not have enough memory for either survivor or promoted objects, or for both. The Java heap cannot because it is already at its maximum. Example messages:
924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space exhausted), 0.1957310 secs]
924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space overflow), 0.1957310 secs]
To alleviate the problem, try the following adjustments:
Increase the value of the -XX:G1ReservePercent option (and the total heap accordingly) to increase the amount of reserve memory for "to-space".
Start the marking cycle earlier by reducing the value of -XX:InitiatingHeapOccupancyPercent.
Increase the value of the -XX:ConcGCThreads option to increase the number of parallel marking threads.
上面是官方建议:
对于Mixed GC,可以增加-XX:G1ReservePercent
选项的值(以及相应的总堆)以增加“to-space”的保留内存量
总共测试四次,如下表格:
最后修改的参数:-XX:GCTimeRatio=100,理论上对于G1垃圾收集器应该是很重要的,因为本身就是强调吞吐量,只是本次测试只是小的测试项目,
而且服务器配置比较渣,只有2个CPU,有些参数无法试验
总结:
我们可以通过官方文档的建议,通过GC日志,结合解析工具,无论是GCeasy还是GC View都是可以的,通过发生GC的原因等问题逐渐调节参数,
官方文档一定要多看几遍,我只是简单浏览而已,后面肯定会仔细看的。
GC调优指南:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html
如何选择垃圾收集器:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html
G1最佳实践:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html#recommendations
G1 GC的一些关键技术:https://zhuanlan.zhihu.com/p/22591838