有哪些常用的 JVM 启动参数?

#Java#面试八股

有哪些常用的 JVM 启动参数?

结论先行:JVM 参数按兼容性分三档——- 标准参数、-X 非标准参数、-XX 扩展参数;按用途只需记住四组:堆大小、收集器与 GC 日志、OOM 现场、诊断查询。调优的起点不是背参数表,而是先把「堆上限 + GC 日志 + OOM 转储」这三件事配齐,其余参数等观察到问题再加。

一、三档参数的区别

档位形态兼容性典型例子
标准参数-version、-cp所有 JVM 实现都必须支持-classpath、-Dkey=value
非标准参数-Xms、-XmnHotSpot 私有,跨版本不保证-Xss、-Xmx
扩展参数-XX:+Flag、-XX:Flag=v最不稳定,随版本增删-XX:+UseG1GC

-XX 有两种写法:布尔型用 + / - 开关(-XX:+PrintGCDetails),数值型用 = 赋值(-XX:MetaspaceSize=256m)。把布尔型写成 = 是最常见的失误,JVM 会拒绝启动并报 Unrecognized VM option,不会静默忽略。

二、堆与栈:先定容量

参数含义经验值
-Xms / -Xmx堆初始值 / 最大值建议两者相等,避免运行期反复扩容
-Xmn新生代大小G1 下不建议显式设置
-Xss单线程栈大小Linux x64 默认 1M,深递归时才调大
-XX:MetaspaceSize元空间首次触发 GC 的阈值只影响触发点,不是上限
-XX:MaxMetaspaceSize元空间上限不设则只受本地内存限制
-XX:MaxDirectMemorySize堆外直接内存上限Netty / NIO 场景必须显式设置

三、收集器与 GC 日志

收集器参数只要记住「选一个 + 给一个停顿目标」:-XX:+UseG1GC -XX:MaxGCPauseMillis=200。日志参数在 JDK 9 之后被统一日志(unified logging)取代,新旧写法不能混用。

目的JDK 8 写法JDK 9+ 统一日志
GC 明细-XX:+PrintGCDetails-Xlog:gc*
日期时间戳-XX:+PrintGCDateStamps:time,uptime 输出装饰器
日志文件与滚动-XX:+UseGCLogFileRotationfile=gc.log:filesize=50m,filecount=5
存活年龄分布-XX:+PrintTenuringDistribution-Xlog:gc+age=trace

四、一份可直接抄的启动脚本

java -server \
  -Xms4g -Xmx4g \
  -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \
  -XX:MaxDirectMemorySize=1g \
  -XX:+UseG1GC -XX:MaxGCPauseMillis=200 \
  -Xlog:gc*,gc+heap=info:file=/var/log/app/gc-%p.log:time,uptime,level,tags:filesize=50m,filecount=5 \
  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/app/oom.hprof \
  -XX:ErrorFile=/var/log/app/hs_err_%p.log \
  -Djava.security.egd=file:/dev/./urandom \
  -jar app.jar

逐行看:-Xms 等于 -Xmx 是为了让堆一次要够;MaxMetaspaceSize 是给容器兜底;gc-%p.log 用进程号区分多实例;HeapDumpOnOutOfMemoryError 是唯一能在事后还原现场的开关,务必打开;urandom 解决容器内熵不足导致的启动卡顿。

五、OOM 与崩溃现场

参数作用
-XX:+HeapDumpOnOutOfMemoryError堆 OOM 时导出 hprof
-XX:HeapDumpPath=/path指定转储路径,容器内要挂载出来
-XX:OnOutOfMemoryError="/bin/kill -9 %p"OOM 后执行脚本,常用于配合重启
-XX:+ExitOnOutOfMemoryErrorOOM 直接退出,交给编排系统拉起
-XX:ErrorFile=/path/hs_err_%p.logJVM 崩溃时的错误日志

注意 OnOutOfMemoryError 和 ExitOnOutOfMemoryError 会互相干扰,只留一个。

六、查询当前生效参数

jcmd 1234 VM.flags                 # 整个 JVM 的参数清单
jinfo -flag MaxHeapSize 1234       # 单个参数的最终取值
jinfo -flags 1234                  # 只看被显式设置的参数
java -XX:+PrintFlagsFinal -version | grep -i heapsize

PrintFlagsFinal 只列 -XX 参数,-Xms 实际上是 -XX:InitialHeapSize 的别名,-Xmx 是 -XX:MaxHeapSize,所以查不到 -Xmx 不代表没生效。

七、常见追问

追问回答要点
为什么 -Xms 要等于 -Xmx堆扩缩本身带来停顿和抖动;容器里用 -XX:MaxRAMPercentage=75 自适应更稳妥
-Xmn 和 -XX:NewRatio 冲突吗同时给时 -Xmn 优先;NewRatio 表示老年代/新生代容量比
元空间会 OOM 吗会,Metaspace 或 Compressed class space 溢出;不设上限则吃光容器内存被 OOMKilled
-XX:+DisableExplicitGC 能用吗能屏蔽业务代码里的 System.gc(),但也会挡掉 DirectByteBuffer 依赖的清理触发,慎用
参数写错会静默忽略吗不会,启动即失败;-XX:+IgnoreUnrecognizedVMOptions 只在跨版本复用脚本时短期使用

小结

参数分三档,实战只需盯住「容量、收集器与日志、现场保留」四条线。先开日志和 dump,再谈调优;任何一个参数上线前,用 jcmd VM.flags 确认它真的生效了。

笔记加载中…