在实际的Java应用开发中,JVM(Java Virtual Machine)调优是提升应用性能的关键步骤。合理的调优可以显著提升应用的响应速度、吞吐量,并且减少内存消耗和GC(Garbage Collection)停顿时间。本文将详细介绍JVM 11的优化指南,包含如何进行JVM调优以及常见的JVM调优参数,并提供3个实用的代码示例。
JVM 调优的基本思路
1、 确定问题:了解当前系统的瓶颈,是CPU、内存、磁盘I/O还是网络I/O。
2、 收集数据:使用工具(如JConsole、VisualVM、Java Mission Control)监控应用的性能数据。
3、 分析数据:通过分析收集的数据,确定哪些参数需要调整。
4、 调整参数:修改JVM参数,并观察调整后的效果。
5、 持续优化:不断迭代调整,直到达到预期的性能指标。
参数介绍:
Java命令行参数可以根据其类型和作用范围大致分为以下三种类型:
标准选项(Standard Options):
- 示例:
-version
,-help
,-showversion
,-classpath
,-Dproperty=value
,-verbose[:class|gc|jni]
,-agentlib:libname[=options]
,-agentpath:pathname[=options]
,-javaagent:jarpath[=options]
等。 - 描述:这些选项是Java语言规范中定义的标准参数,跨不同JDK版本和实现保持一致,用于设置基本的Java运行环境、类路径、系统属性、日志级别、JAR包代理、启动画面等。它们通常以单个短横线(
-
)开头,不带有额外的前缀。
非标准(或扩展)选项(Non-standard / Extended Options):
- 示例:
-Xms<size>
,-Xmx<size>
,-Xss<size>
,-Xmn<size>
,-Xlog[:options]
,-Xms1024m
,-Xmx2048m
,-Xss1024k
,-Xverify:none
,-Xbootclasspath:<path>
,-Xint
,-Xcomp
,-Xmixed
,-Xincgc
,-Xnoclassgc
,-Xrs
,-Xcheck:jni
等。 - 描述:这些选项以
-X
前缀开头,属于非标准或扩展选项,用于设置特定JVM实现提供的、超出标准选项范围的特性。它们可能随JDK版本变化,且不同JDK供应商可能提供不同的-X
选项。这类选项通常用于调整JVM的内存大小、垃圾收集行为、编译策略、类加载行为、JNI检查等。
非稳定(或内部)选项(Non-stable / Internal Options):
- 示例:
-XX:+UseG1GC
,-XX:InitialHeapSize=size
,-XX:MaxHeapSize=size
,-XX:NewRatio=ratio
,-XX:SurvivorRatio=ratio
,-XX:MaxTenuringThreshold=threshold
,-XX:+UseConcMarkSweepGC
,-XX:+UseSerialGC
,-XX:+UseParallelGC
,-XX:+UseParallelOldGC
,-XX:+UseAdaptiveSizePolicy
,-XX:MetaspaceSize=size
,-XX:MaxMetaspaceSize=size
,-XX:TargetSurvivorRatio=ratio
,-XX:MaxDirectMemorySize=size
等。 - 描述:这些选项以
-XX
前缀开头,属于非稳定或内部选项,用于调整JVM的非常具体的、底层的、可能随JDK版本变化的特性。它们通常用于高级的JVM调优,如详细控制垃圾收集器的选择和行为、内存区域大小、编译器优化、元空间配置、栈大小等。使用这类选项需要深入了解JVM内部工作原理,因为误用可能导致性能下降或不稳定。由于它们的非稳定性,JDK文档可能不会详尽描述所有-XX
选项,且不同JDK版本或供应商可能提供不同的选项。
对于 JVM 调优,主要就是调整年轻代、老年代、元空间的内存空间大小及使用的垃圾回收器类型。
比较常用的 JVM 调优用的参数如下:
- 设置堆空间大小。
- 虚拟机栈的设置。
- 年轻代中 Eden 区和两个 Survivor 区的大小比例。
- 年轻代晋升老年代阈值。
- 设置垃圾回收收集器。
设置堆空间大小
设置堆空间大小
:设置堆的初始内存和最大内存,为了防止垃圾收集器在初始大小、最大大小之间收缩堆而产生额外的时间,通常把最大、初始大小设置为相同的值。这里主要包括两个参数:
-Xms
:设置堆的初始化内存大小。-Xmx
:设置堆的最大大小。
这两个参数如果不指定单位默认为字节,如果指定单位,按照指定的单位设置。如下所示:
# 设置初始内存大小为 1024B
-Xms:1024
# 设置初始内存大小为 1024KB
-Xms:1024k
# 设置初始内存大小为 1024MB
-Xms:1024m
# 设置初始内存大小为 1GB
-Xms:1g
堆空间大小设置多少合适?
- 最大大小的默认值是物理内存的 1/4,初始大小是物理内存的 1/64。
- 堆太小,可能会频繁的导致年轻代和老年代的垃圾回收,会产生stw,暂停用户线程,这是不合适的。
- 堆太大,内存大肯定是好的,但是存在风险,如果发生了 Full GC,它会扫描整个堆空间,暂停用户线程的时间会特别长,这也是不合适的。
虚拟机栈的设置
虚拟机栈的设置
:每个线程默认会开启 1M 的内存,用于存放栈帧、调用参数、局部变量等,但一般 256K 就够用。通常减少每个线程的栈帧,可以产生更多的线程,但这实际上还受限于操作系统。
可以使用 -Xss
堆每个线程栈帧 stack 大小进行调整,如下所示:
-Xss 256k
设置垃圾回收器
设置垃圾回收器
:通过增大吞吐量提高系统性能,可以通过设置 G1 垃圾回收收集器。
# JDK8 默认是并行垃圾收集器
-XX:+UseParallelGC
-XX:+UseParallelOldGC
# 设置 G1 垃圾收集器(JDK9默认)
-XX:+UseG1GC
设置过后,我们就可以在项目中使用 G1 垃圾收集器了。