当你想要进行JVM调优时,首先你要对自己的系统有清晰的认识,其次也要明确,调优并非万用的,需要视具体情况而定, 有时升级新版本的JDK带来的效果可能要比调优带来的效果更加显著;调优的过程也大致分为:确立目标,调试优化,结果验收

JVM参数简介

既然要调优,那我们需要对JVM参数有一定的认识,如下是我们常用一些参数:

常用参数

参数 示例 语义
-XX:+PrintCommandLineFlags 输出启动参数
-Xmxsize -Xmx1024m 最大堆大小
-Xmssize -Xms512m 初始堆大小
-Xmnsize -Xmn256m 新生代大小
-Xsssize -Xss1m 线程栈大小
-XX:MaxNewSize=size -XX:MaxNewSize=128m 最大新生代大小
-XX:MetaspaceSize=size 元数据区大小
-XX:MaxMetaspaceSize=size 最大元数据区大小
-XX:TLABSize=size 线程缓存区大小
-XX:NewRatio=ratio 默认2 占整个堆的1/(ratio+1)
-XX:SurvivorRatio=ratio 默认8 占整个新生代的1/(ratio+1)
-XX:MaxTenuringThreshold=Threshold 晋升到年龄大小
-XX:PretenureSizeThreshold=Threshold Serial,ParNew有效 对象直接晋升大小阈值

垃圾收集相关参数

参数 示例 语义
-verbose:gc -verbose:gc 显示每次GC的情况
-Xloggc:filename -Xloggc:gc.log 将GC日志输出到gc.log文件
-XX:+PrintGCDetails 输出GC详细信息
-XX:+TraceClassLoading -XX:+TraceClassLoading 追踪类加载信息
-XX:+TraceClassUnloading -XX:+TraceClassUnloading 追踪类卸载信息
-XX:+HeapDumpOnOutOfMemoryError 内存溢出时输出dump文件
-XX:+TLAB 默认开启 使用线程分配缓存区
-XX:+UseParallelGC 使用Parallel收集器
-XX:+UseG1GC 使用G1收集器
-XX:+UseSerialGC 使用Serial收集器
-XX:+UseParNewGC 使用ParNew收集器
-XX:+UseConcMarkSweepGC 使用CMS收集器

TIPS

常用工具介绍

-XX:+PrintFlagsFinal

java -XX:+PrintFlagsFinal -version |grep G1

image-1655538739158

工欲善其事必先利其器,利用JDK自带的一些工具起来,可以让我们定位问题的时候事半功倍。

jinfo 查看正在运行JVM参数

-- jps 命令获取当前正常运行的java进程id
jps -l 
-- 查看所有参数
jinfo pid

-- 查看指定pid的JVM运行的参数信息
jinfo -flags pid

也可以在启动是添加-XX:+PrintCommandLineFlags,虚拟机启动时也会打印参数信息。

jinfo官方文档

jmap 常用示例

输出堆中各区使用情况

  • 示例: jmap -heap <pid>

image-1655135699294

输出堆快照

  • 示例: jmap -dump:live,format=b,file=heap.hprof <pid>

jmap官方文档

jstat 常用示例

jstat 官方文档

以一定时间比例输出GC情况

  • 示例: jstat -gcutil <pid> <ms>

image-1655135714222

S0表示Survivor 0区占用比例
S1表示Survivor 1区占用比例
E 表示Eden区占用比例
O 表示Old区占用比例
M 表示Metaspace区占用比例
CCS 表示压缩使用比例
YGC 表示Young GC 次数
YGCT 表示Young GC 耗时
FGC 表示Full GC 次数
FGCT 表示Full GC 耗时
GCT 表示GC 总耗时

jstack 常用示例

输出线程快照

  • 示例: jstack <pid>

jvisualvm

image-1655135733791

jconsole

image-1655135748652

GC日志识别

前面我们介绍了一些参数,以及工具的使用,我们该如何去读GC日志呢?不同的垃圾收集器输出的日志,稍有差异,但其核心内容基本都大同小异。

GC日志

image-1655135763591

Full GC日志

image-1655135774961

实战参考

实战参考美团GC调优的过程

Parallel常用参数

  • -XX:+UseParallelGC 开启ParallelGC

  • -XX:SurvivorRatio

  • -XX:PreTenureSizeThreshold 大对象直接进入Old区的大小

  • -XX:MaxTenuringThreshold 晋升到老年代阈值

CMS常用参数

  • -XX:+UseConcMarkSweepGC 开启CMS

  • -XX:CMSInitiatingOccupancyFraction 使用多少比例老年代开始CMS收集,默认68%(近似值),如果频繁发生SerialOld卡顿,应该调小。

  • -XX:+UseCMSCompactAtFullCollection 在CMS时开启压缩,解决碎片化,或者浮点垃圾

  • -XX:CMSFullGCsBeforeCompaction 在CMS多少次FullGC之后,开始压缩

  • -XX:+CMSClassUnloadingEnabled 允许方法区回收

  • -XX:MaxGCPauseMillis 停顿时间,一个建议参数

  • -XX:GCTimeRatio GC时间占运行时间的百分比

G1常用参数

  • -XX:+UseG1GC 开启G1

  • -XX:MaxGCPauseMillis 停顿时间,一个建议参数

  • -XX:G1HeapRegionSize G1的Region大小,建议逐步调整该值;1,2,4,8,16,32 ;随着size的增大,垃圾存活时间更长,GC间隔更长,但每次GC时间也会变长。

  • -XX:G1NewSizePercent 默认5,新生代最小比例

  • -XX:G1MaxNewSizePercent 默认60,新生代最大比例

  • -XX:GCTimeRatio 建议GC时间占比

  • -XX:ConcGCThreads 并发GC线程数

  • -XX:InitiatingHeapOccupancyPercent 启动G1的百分比