JVM参数调优教程


一提到 JVM 参数调优,脑海中第一眼浮现就是面试八股文,但在日常的开发中,有时间一个不起眼的参数总能给你带来意想不到的效果。

正所谓技多不压身,今天让我们一起来揭开 JVM 调优的神秘面纱。

一、参数配置

1. 配置方式

在虚拟机中 -X-D 都可用于指定 JVM 参数,但它们在使用方式和作用范围上有一些区别。

(1) -X 方式

-X 用于指定非标准的 JVM 参数,这些参数通常是供具体的 JVM 实现或特定的虚拟机选项使用的。

例如 -X<parameter>,其中 <parameter> 是具体的 JVM 参数名称。

(2) -D 方式

-D 用于设置系统属性,提供了一种在应用程序中传递配置信息的机制,可以在应用程序中通过 System.getProperty() 方法获取。

例如 -D<property>=<value>,其中 <property> 是属性名称,<value> 是属性值。

(3) 基本格式

JVM 配置参数通常由 -XX: 开头,基本格式如下:

  • 若用于配置是否启用,由 + - 分别控制开启与关闭。
  • 若用于配置大小或数值变量,遵循 <option>=<value> 格式。
# 表示开启 option 选项
-XX:+<option>

# 表示关闭 option 选项
-XX:-<option>    

# 表示将 option 值赋为 value
-XX:<option>=<value>    

2. 优先级

Java 命令行运行 JAR 包时,JVM 参数可以在 -jar 选项之前或之后指定,这两种方式会影响参数的解析和执行顺序。

  • 参数在 -jar 之前,则会在 JVM 启动前解析和应用。
  • 参数在 -jar 之后,则会在解析 JAR 包时被应用。
  • JVM 参数与 JAR 包的命令行参数存在冲突,JVM 参数的优先级更高。

如下示例中方式一的 -Xmx512m 优先级高于方式二中的 -Xmx1024m

# 方式一
java -Xmx512m -jar myapp.jar

# 方式二
java -jar myapp.jar -Xmx1024m

二、常用配置

1. 内存参数

在默认的 JVM 服务启动中,如果没有手动指定堆内存值,则默认的取值方式如下:

  • 最小值:通常是物理内存大小的 1/64,但不超过 1GB,可通过 -Xms 参数指定。
  • 最大值:通常是物理内存大小的 1/4,但不超过 32GB,可通过 -Xmx 参数指定。

常见的 JVM 内存参数如下:

# 堆内存初始值
-Xms1G 

# 堆内存最大值
-Xmx2G

# 每个线程的堆栈大小,默认 1MB,在相同物理内存下,减小这个值能生成更多的线程
# 但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在 3000~5000 左右
-Xss512k

# 设置年轻代大小,增大年轻代后,将会减小年老代大小。
# 此值对系统性能影响较大,Sun 官方推荐配置为整个堆的 3/8。
-Xmn1024m

2. JVM参数

针对于 JVM 的内存堆 (Heap) 以及垃圾回收,常见的配置参数如下:

# CMS垃圾回收器并行线程线,推荐值为CPU核心数。
-XX:ConcGCThreads=4

# 新生代并行收集器的线程数。
-XX:ParallelGCThreads=8

# 设置新生代中 Eden 与 Survivor 的比例,默认为 8,即 8:1:1
-XX:SurvivorRatio=8

# 直接晋升到老年代的对象大小
# 设置该值后将忽略 MaxTenuringThreshold 设置,当对象大小达到设置值后直接晋升老年代
-XX:PretenureSizeThreshold=1m

# 设置垃圾最大年龄,取值 0~15,默认为 15
-XX:MaxTenuringThreshold=10

3. 系统参数

常见的系统参数配置参数如下:

# 防止虚拟机阻塞
-Djava.security.egd=file:/dev/./urandom

4. GC参数

常见的虚拟机垃圾回收(GC)参数配置参数如下:

开启日志后生成的 GC 信息文件可通过工具进行分析,推荐在线分析网站:https://gceasy.io

# 打印 gc 发生的时间戳
-XX:+PrintGCDateStamps

# 打印 gc 发生时的分代信息
-XX:+PrintTenuringDistribution

# 打印 gc 停顿时长
-XX:+PrintGCApplicationStoppedTime

# 打印 gc 间隔的服务运行时长
-XX:+PrintGCApplicationConcurrentTime

# 打印 gc 详情,包括 gc 前/内存等
-XX:+PrintGCDetails

# 指定 gc log 的路径,存放于当前 gclogs 目录下的 gc.log.date 文件
-Xloggc:./gclogs/gc.log.date

三、JDK工具

1. Jinfo

jinfoJDK中的一个命令行工具,用于实时查看和调整 Java 虚拟机(JVM)的配置信息。

通过 jinfo 可以获取和修改正在运行的 Java 进程的虚拟机配置参数,对于调优和诊断 Java 应用程序是很有帮助的。

# 查看进程的虚拟机参数信息
jinfo <options> <pid>
(1) flags

显示所有可用的虚拟机参数及其当前值。

jinfo -flags <pid>

(2) flag

显示指定标志的值。

jinfo -flag <name> <pid>

# 查看 pid 为 123 的 ThreadStackSize 参数信息
# 输出: -XX:ThreadStackSize=1024
jinfo -flag ThreadStackSize 123
(3) -flag [+|-]

启用或禁用指定的标志。

# 开启配置
jinfo -flag +<name> <pid>

# 关闭配置
jinfo -flag -<name> <pid>
(4) sysprops

显示 Java 系统属性的值。

jinfo -sysprops <pid>

2. Jstat

jstatJDK 中的一个命令行工具,用于监视 Java 虚拟机 (JVM) 的各种统计信息。

它提供了对堆内存、垃圾回收、类装载、JIT 编译等方面的实时性能数据,帮助开发人员和系统管理员诊断和分析 Java 应用程序的性能问题。

# <pid>: jps process id
# <interval>: time interval, ms
jstat -gc <pid> <interval>


# Simple info
jstat -gcutil <pid> <interval>



  • S0C:年轻代中第一个 Survivor(幸存区)的容量 (KB) 。
  • S1C:年轻代中第二个 Survivor(幸存区)的容量 (KB)。
  • S0U:年轻代中第一个 Survivor(幸存区)目前已使用空间 (KB) 。
  • S1U:年轻代中第二个 Survivor(幸存区)目前已使用空间 (KB) 。

  • EC:年轻代中 Eden(伊甸园)的容量 (KB) 。
  • EU:年轻代中 Eden(伊甸园)目前已使用空间 (KB)。

  • OCOld 代的容量 (KB) 。
  • OUOld 代目前已使用空间 (KB) 。

  • MC:元数据区的容量 (KB) 。
  • MU:元数据区目前已使用空间 (KB) 。

  • YGC:从应用程序启动到采样时年轻代中 GC 次数 。
  • YGCT:从应用程序启动到采样时年轻代中 GC 所用时间(秒) 。

  • FGC:从应用程序启动到采样时 OldFull GC 次数 。
  • FGCT:从应用程序启动到采样时 OldFull GC 所用时间(秒) 。
  • GCT:从应用程序启动到采样时 GC 用的总时间(s) 。

  • NGCMN:年轻代 (Young) 中初始化(最小)的大小 (字节) 。
  • NGCMX:年轻代 (Young) 的最大容量 (字节) 。
  • NGC:年轻代 (Young) 中当前的容量 (字节) 。

  • OGCMNOld 代中初始化(最小)的大小 (字节) 。
  • OGCMXOld 代的最大容量 (字节) 。
  • OGCOld 代当前新生成的容量 (字节) 。
  • OOld 代已使用的占当前容量百分比。

  • S0:年轻代中第一个 Survivor(幸存区)已使用的占当前容量百分比。
  • S1:年轻代中第二个 Survivor(幸存区)已使用的占当前容量百分比 。
  • S0CMX:年轻代中第一个 Survivor(幸存区)的最大容量 (字节) 。
  • S1CMX :年轻代中第二个 Survivor(幸存区)的最大容量 (字节) 。
  • E:年轻代中 Eden(伊甸园)已使用的占当前容量百分比 。
  • ECMX:年轻代中 Eden(伊甸园)的最大容量 (字节) 。

  • DSS:当前需要 Survivor(幸存区)的容量 (字节)( Eden 区已满)。
  • TT: 持有次数限制。
  • MTT : 最大持有次数限制。

3. Jstack

jstackJDK中的一个命令行工具,用于生成 Java 进程的线程转储(thread dump)。

线程转储是一个描述 Java 虚拟机中所有线程当前状态的快照,包括线程的堆栈信息。

# 查询进程堆栈信息
jstack [options] <pid>


# <line num>: 限制显示行数
# <pid_16>: 进程转十六进制
jstack <pid> | grep -A <line num> <pid_16_hex>

# 转十六进制
printf '%x\n' <pid>
(1) -l

除了线程堆栈外,还显示关于锁的附加信息,这将显示每个锁的拥有者和等待者。

jstack -l <pid>
(2) -F

当进程无响应时,强制生成线程转储,在进程卡死或无响应时非常有用。

jstack -F <pid>
(3) -m

打印 Java 和本地 C/C++ 帧的混合堆栈。

jstack -m <pid>
(4) -e

打印线程的锁信息。

jstack -e <pid>

4. JMap

jmapJDK 中的一个命令行工具,用于生成 Java 进程的内存转储快照。

这个快照通常称为 heap dump,它是 Java 堆内存的详细信息,包括对象的数量、类型、分布等,对于分析内存泄漏和性能问题非常有用。

jmap [options] <pid>
(1) -heap

打印 Java 堆内存的概要信息,包括堆的使用情况和配置。

jmap -heap <pid>

(2) -heap

打印 Java 堆内存中对象的直方图,显示每个类的实例数量和占用的内存大小。

jmap -histo <pid>
(3) -dump

生成堆转储文件,将 Java 堆内存的详细信息保存到指定的文件中。

在线 dump 文件分析工具:https://heaphero.io/index.jsp

jmap -dump:file=<export_path> <pid>


# 生成堆栈信息日志
jmap -dump:format=b,file=./dump.bin 123
(4) -F

当进程无响应时,强制生成堆转储,在处理无响应或死锁的情况下很有用。

jmap -F -dump:file=<dumpfile> <pid>

参考文档

  1. JVM常用调优参数 ——JVM篇
  2. 一次简单的 JVM 调优,拿去写到简历里
  3. jstat命令查看jvm内存情况及GC内存变化

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录