1.前言
在实际生产环境中,我们经常需要在部署我们服务之前对JVM进行预调优,预调优完后,一定一定需要进行压测,根据压测结果进行调整,找到最合适的调优参数。
2.JVM预调优
下面有几个建议:
1.生产上JVM的调优是需要提前规划的,并且一般只有像架构师这种级别的,比较熟悉我们的业务场景,进行预调优才比较有效果。
2.我们设置完JVM预调优参数后,是需要进行压测,根据压测结果进行调整的,不可能一次到位,调优是没有最好,只有更好
3.在预调优阶段,我们是需要对JVM进行监控的,这样你进行压测,我们才能通过监控知道我们设置的JVM参数有没有效果。一般预调优是在上生产之前,所以我们可以直接在需要部署服务的机器上面开启JMX,通过windows 下JDK自带的jconsole或者jvisualvm进行远程连接,不断观察JVM状况。但是上生产一定要把**监控关掉**,因为监控本身就是一种耗性能的操作。或者开起日志进行观察(开启方式见下文第6点.设定日志参数,但是日志不太直观),具体jconsole或者jvisualvm这些监控工具在下文进行进一步阐述。进行规划的步骤
1.熟悉业务场景,明确是需要响应时间,还是吞吐量。
响应时间 :意味着你需要降低GC的STW停顿时间,那这个时候可以选择[CMS G1 ZGC]
吞吐量:用户代码执行时间/[用户代码执行时间+GC时间],意味着GC时间越短吞吐量越高,这个时候可以选择PS
2.根据业务需要选择合适的回收器,常见回收器选择,分别是年轻代和老年代的搭配。
【Serial,SerialOld】这个基本已经没有使用了,因为他是单线程回收。适合JVM内存只有几十M的场景
【Parallel Scavenge,ParallelOld】目前这个回收器组合是比较场常见的,JD8默认的回收器选择
【ParNew ConcurrentMarkSweep】这个在JDK默认是不开启的,当我们设置参数-XX:+UseConcMarkSweepGC 的时候,就会设置JVM的参数为这种回收器选择
【G1】这是JDK1.9默认的回收器选择,物理不分代,只是逻辑分代
【ZGC】这是在JDK11出现,还在试验阶段,本人现在还不是很了解
3.设置内存大小
没有说一定是内存越大越好,因为内存如果越大,意味着一次fullGC耗时更多。
一般情况下,我们需要设置-Xms40M -Xmx40M 最大和最小堆大小一致,防止JVM的内存频繁伸缩耗系统资源。
4.CPU选择
这个没有纠结的,一定是CPU越高越好,提高计算能力
5.设定年代大小、升级年龄
这个一般没有去修改,下面是从oracle摘抄的对升级到老年代需要经过多少次GC的描述
如何计算我们需要多大JVM内存呢?需要根据业务,假设每秒最高并发1000,那么建设会创建的对象大小为512K(足够了),那么需要的内存为1000*512K=500M左右。那么你可以设置年轻代为500M老年代为1G。当然我这是理论算法的,具体还是以压测实际结果为准
如果需要对年代大小内存占比需要了解,可以看下我这篇文章:
XX:MaxTenuringThreshold=threshold
Sets the maximum tenuring threshold for use in adaptive GC sizing. The largest value is 15. The default value is 15 for the parallel (throughput) collector, and 6 for the CMS collector.
The following example shows how to set the maximum tenuring threshold to 10:
-XX:MaxTenuringThreshold=106.设定日志参数
一般生产上面会配置日志生成多个小文件,滚动更新。下面的配置的含义是生产GC日志5份,每份最大20M,当放不下的时候,会把最开始的日志进行滚动覆盖更新。
-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
















