JVM 参数及调优
调优基本概念
在调整 JVM 性能时,通常有三个组件需要考虑:
- 堆大小调整
- 垃圾收集器调整
- JIT 编译器
大多数调优选项都与调整堆大小和选择合适的垃圾收集器有关,JIT 编译器对性能也有很大影响,但很少需要对其进行调优,尤其是针对较新版本的 JVM。
通常,在进行 Java 程序调优的时候,会重点关注两个主要指标:
- 响应性:应用程序对请求进行响应的速度,对于专注响应性的应用程序,长时间的暂停是不可接受的,需要在最短时间内做出响应
- 吞吐量:侧重于在特定时间内最大化应用程序的工作量,对于专注于吞吐量的应用程序,符合要求的暂停是可以接受的。
JVM 本身是在不断优化的,系统瓶颈的核心还是在于应用代码,更多的情况下还是要专注于应用代码的优化。
常用 JVM 参数
参数 | 描述 |
---|---|
-XX:+AlwaysPreTouch | JVM 启动时分配内存,堆的每个页面都在初始化期间按需置零,而不是在应用程序执行期间递增 |
-XX:Errorfile = filename | 错误日志 |
-XX:+TraceClassLoading | 跟踪类加载信息 |
-XX:+PrintClassHistogram | 按下 Ctrl+Break 后打印类信息 |
-Xmx -Xms | 最大堆 最小堆 |
-xx:permSize | 永久代大小 |
-xx:metaspaceSize | 元数据空间大小 |
-XX:+HeapDumpOnOutOfMemoryError | 当抛出 OOM 时进行 HeapDump |
-XX:+HeapDumpPath | OOM 时堆导出的路径 |
-XX:OnOutOfMemoryError | 当发生 OOM 时执行用户指定的命令 |
命令: java -XX:+PrintFlagsFinal -version 会 打印所有的 - XX 参数及其默认值
GC 调优思路
- 分析场景,如:启动速度慢,偶尔出现响应慢于平均水平或出现卡顿
- 确定目标,如:内存占用,低延时,吞吐量
- 收集日志,如:通过参数配置收集 GC 日志,通过 JDK 工具查看 GC 状态
- 分析日志,如:使用工具辅助分析日志,查看 GC 次数,GC 时间
- 调整参数,如:切换垃圾收集器或者调整垃圾收集器参数
常用 GC 参数
参数 | 描述 |
---|---|
-XX:ParallelGCThreads | 并行 GC 线程数量 |
-XX:ConcGcThreads | 并发 GC 线程数量 |
-XX:MaxGCPauseMillis | 最大停顿时间,单位毫秒,GC 尽力保证回收时间不超过设定值 |
-XX:GCTimeRatio | 垃圾收集时间占总时间的比值,取值 0-100,默认 99,即最大允许 1% 的时间做 GC |
-XX:SurvivorRatio | 设置 eden 区大小和 survivor 区大小的比例,8 表示两个 survivor:eden=2:8,即一个 survivor 占年轻代的 1/10 |
-XX:NewRatio | 新生代和老年代的比,4 表示新生代:老年代 = 1:4,即年轻代占堆的 1/5 |
-verbose:gc,-XX:+PrintGC | 打印 GC 的简要信息 |
-XX:+PrintGCDetails | 打印 GC 详细信息(JDK9 之后不再使用) |
-XX:+PrintGCTimeStamps | 打印 GC 发生的时间戳(JDK9 之后不再使用) |
-Xloggc:log/gc.log | 指定 GC log 的位置,以文件输出 |
-XX:PrintHeapAtGC | 每次 GC 后都打印堆信息 |
垃圾收集器 Parallel 参数调优
Parallel 垃圾收集器在 JDK8 中是 JVM 默认的垃圾收集器,它是以吞吐量优先的垃圾收集器。其可调节的参数如下:
参数 | 描述 |
---|---|
-XX:+UseParallelGC | 新生代使用并行垃圾收集器 |
-XX:+UseParallelOldGC | 老年代使用并行垃圾收集器 |
-XX:ParallelGCThreads | 设置用于垃圾回收的线程数 |
-XX:+UseAdaptiveSizePolicy | 打开自适应 GC 策略 |
垃圾收集器 CMS 参数调优
CMS 垃圾收集器是一个响应时间优先的垃圾收集器,Parallel 收集器无法满足应用程序延迟要求时再考虑使用 CMS 垃圾收集器,从 JDK9 开始 CMS 收集器已不建议使用,默认用的是 G1 垃圾收集器。
参数 | 描述 |
---|---|
-XX:+UseConcMarkSweepGC | 新生代使用并行收集器,老年代使用 CMS + 串行收集器 |
-XX:+UseParNewGC | 新生代使用并行收集器,老年代 CMS 收集器默认开启 |
-XX:CMSInitiatingOccupanyFraction | 设置触发 GC 的阈值,默认 68%,如果内存预留空间不够,就会引起 concurrent mode failure |
-XX:+UseCMSCompactAtFullCollection | Full GC 后,进行一次整理,整理过程是独占的,会引起停顿时间变长 |
-XX:+CMSFullGCsBeforeCompaction | 设置进行几次 Full GC 后进行一次碎片整理 |
-XX:+CMSClassUnloadingEnabled | 允许对类元数据进行回收 |
-XX:+UseCMSInitiatingOccupanyOnly | 表示只在达到阈值的时候才进行 CMS 回收 |
-XX:+CMSIncrementalMode | 使用增量模式,比较适合单 CPU |
垃圾收集器 G1 参数调优
G1 收集器是一个兼顾吞吐量和响应时间的收集器,如果是大堆(如堆的大小超过 6GB), 堆的使用率超过 50%,GC 延迟要求稳定且可预测的低于 0.5 秒,建议使用 G1 收集器。
参数 | 描述 |
---|---|
-XX:G1HeapRegionSize | 设置 Region 大小,默认 heap/2000 |
-XX:G1MixedGCLiveThresholdPercent | 老年代依靠 Mixed GC, 触发阈值 |
-XX:G1OldSetRegionThresholdPercent | 定多包含在一次 Mixed GC 中的 Region 比例 |
-XX:+ClassUnloadingWithConcurrentMark | G1 增加默认开启,在并发标记阶段结束后,JVM 即进行类型卸载 |
-XX:G1NewSizePercent | 新生代的最小比例 |
-XX:G1MaxNewSizePercent | 新生代的最大比列 |
-XX:G1MixedGCCountTraget | Mixed GC 数量控制 |
调优示例
GC 分析主要查看 GC 导致的 Stop The World 的时间,它会导致程序的延时增加。
示例代码运行的时候建议指定其堆内存的最大值,启动时添加 JVM 参数 - Xmx1024m。程序运行起来之后可以利用 jps 或者 jcmd 产看运行的程序进程号。
拿到进程号之后利用 jstat 命令查看 GC 信息,如动态监控 GC 统计信息,间隔 1000 毫秒统计一次,每 10 行数据后输出列标题:
上述两个步骤也可以合并成一个 jstat -gc -h10 $(jcmd | grep “com.example.springbootdemo.SpringBootDemoApplication” | awk ‘{print $1}’) 1000
当然除了动态监控 GC 信息,也可以将 GC 日志信息打印到文件,然后利用 GC 分析工具进行分析。
在程序启动时添加 JVM 参数”-Xmx1024m -Xloggc:/gc.log“,则可以可以将 GC 日志打印到 gc.log 文件,然后可以利用 GCViewer 工具辅助分析 GC 日志文件,参考地址:https://github.com/chewiebug/GCViewer
GCViewer 下载后双击 gcviewer-x.xx-SNAPSHOT.jar 文件即可运行,然后将 gc.log 日志文件导入即可观察 GC 信息。
GC 调优之前,我们需要了解当前 JVM 参数的信息。命令 java -XX:+PrintFlagsFinal -version 会打印所有的 JVM 参数,如需查看指定参数,如查看 UseAdaptiveSizePolicy 的值可以使用 java -XX:+PrintFlagsFinal -version | grep UseAdaptiveSizePolicy
调整 - XX:ParallelGCThreads 的值可以指定 GC 并发的线程数,如在 JVM 启动参数中可以添加 “-Xmx1024m -XX:ParallelGCThreads=4”,调节 GC 并发的线程数,观察 GC 的信息,如 Full GC 次数 FGC,Full GC 的总时间 FGCT,GC 的总时间 GCT 等进行调优。
同样我们可以在 JVM 启动参数中指定 - XX:MaxGCPauseMills,使用 G1 收集器 - XX:+UseG1GC 等,调节 JVM 启动参数,收集 GC 日志,更具监控进行相应的调节,进而找到最优值。
还没有评论,来说两句吧...