有哪些常用的 JVM 启动参数?
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
-
基础认知
面试官想确认你是否知道 JVM 参数的基本分类(标准参数、-X 非标准参数、-XX 高级参数),以及每一类参数的作用边界。 -
常用实战经验
不仅仅是想让你背参数列表,更想知道你在真实项目里用过哪些参数,比如堆大小设置、垃圾回收器选型、OOM 时生成 HeapDump 等。有没有通过参数解决过内存溢出、高延迟问题。 -
版本差异意识
你是否知道 JDK 8 与 JDK 11/17 在参数上的变化(如 PermGen → Metaspace,-XX:+PrintGCDetails被废弃)。面试官希望候选人能意识到版本演进对调优的影响,而不是只会背诵老旧的参数。 -
排查与调优思路
从你选择的参数中,可以侧面推断你的问题排查习惯(是否开启 GC 日志、是否启用 JMX 远程监控、是否在压测时调整过并行 GC 线程数等)。
核心答案
我将 JVM 常用启动参数按功能域划分为 5 大类,并挑选了生产环境最常用、面试最高频的部分。所有参数均以 JDK 11 / 17 为准,并标注了相对于 JDK 8 的关键变化。
1. 堆内存设置
# 初始堆大小,生产环境建议与 -Xmx 设相同,避免动态伸缩
-Xms4g
# 最大堆大小
-Xmx4g
# 新生代大小,通常设为堆的 1/3 ~ 1/2
-Xmn2g
# 或者使用 -XX:NewRatio 设置新生代与老年代比例
-XX:NewRatio=2
# 元空间(替代 JDK 8 之前的永久代)初始大小与最大大小
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=256m
2. 垃圾回收器选择与调优
JDK 11/17 默认 G1,如需显式指定:
# 使用 G1 垃圾回收器(JDK9+ 默认)
-XX:+UseG1GC
# 设置 G1 期望的最大停顿时间,默认 200ms
-XX:MaxGCPauseMillis=100
# 并行 GC 线程数,一般设为 CPU 核心数的 1/4 ~ 1/2
-XX:ParallelGCThreads=8
# 并发 GC 线程数
-XX:ConcGCThreads=2
若对吞吐量有极致要求,可选用 Parallel GC:
-XX:+UseParallelGC
-XX:+UseParallelOldGC # JDK 8 之后合并,显式指定兼容老版本
3. 故障排查与日志
JDK 9+ GC 日志统一使用 -Xlog
# 输出详细 GC 日志(文件轮转)
-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=5,filesize=20m
# 发生 OOM 时自动导出堆快照
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/logs/heapdump.hprof
# 记录应用暂停时间(建议配合 GC 日志分析)
-XX:+PrintGCApplicationStoppedTime
4. 系统与调试
# 显示参数细节(排查参数是否生效)
-XX:+PrintCommandLineFlags
-XX:+PrintFlagsFinal
# 设置系统网络超时等,避免 DNS 缓存问题
-Dsun.net.client.defaultConnectTimeout=5000
-Dsun.net.client.defaultReadTimeout=5000
# 远程 JMX 监控(生产谨慎开放)
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
5. 类加载与编译
# 打印类加载/卸载信息,排查类冲突
-XX:+TraceClassLoading
-XX:+TraceClassUnloading
# 分层编译,JDK 8+ 默认开启,提升启动速度
-XX:+TieredCompilation
深度解析
原理与机制
-
-Xms 与 -Xmx 设置为相同值
避免 JVM 在运行时动态申请内存、进行堆扩容或缩容。扩容过程会触发 Full GC(尤其是 CMS,JDK 14 移除),造成应用停顿。设成一致后,堆内存自始至终固定,减少性能抖动。 -
Metaspace 取代 PermGen
JDK 8 开始,永久代被元空间替代。元空间使用本地内存(Native Memory),而非 JVM 堆内存。它的默认最大值非常大(受限于物理内存),所以生产环境务必通过-XX:MaxMetaspaceSize限制,防止因类加载过多导致操作系统 OOM Killer。类元数据不再发生java.lang.OutOfMemoryError: PermGen,但依然可能因为元空间扩容触发 Full GC。 -
-Xlog:gc 语法解析*
JDK 9 引入统一日志框架。-Xlog:gc*表示输出所有带gc标签的日志;:file=gc.log输出到文件;time,uptime,level,tags是装饰器,显示时间戳、运行时间、日志级别、标签;filecount=5,filesize=20m实现文件轮转,避免单个文件过大。这是 JDK 11+ 的标准做法,老式-XX:+PrintGCDetails虽然仍支持,但已不推荐。
代码示例(启动脚本片段)
#!/bin/bash
JAVA_OPTS="
-server
-Xms4g -Xmx4g
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-Xlog:gc*:file=/var/log/myapp/gc.log:time,uptime:filecount=10,filesize=10m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/myapp
-Djava.awt.headless=true
"
java $JAVA_OPTS -jar myapp.jar
对比分析
| 参数类别 | 示例 | 生效范围 | 是否稳定 | 备注 |
|---|---|---|---|---|
| 标准参数 | -server, -Dprop=value | 所有 JVM 实现 | 稳定 | 不会因 JDK 升级轻易改变 |
| -X 参数 | -Xmx, -Xloggc | 大部分 HotSpot 实现 | 较稳定 | 可能被废弃(如 -Xloggc 被 -Xlog 取代) |
| -XX 参数 | -XX:+UseG1GC, -XX:MaxRAM | HotSpot 特有 | 不稳定 | 随时可能移除,生产慎用不稳定参数 |
最佳实践
-
先稳定,后调优
不要一开始就加大量-XX参数。先用默认参数运行,通过 GC 日志、监控工具发现瓶颈,再有针对性地调整。 -
内存参数必须显示设置
云原生容器环境下,务必设置-Xmx和-XX:MaxMetaspaceSize,否则 JVM 会按宿主机内存自动分配,导致容器被 Kill。JDK 11 开始可通过-XX:MaxRAMPercentage=70.0等百分比参数适配容器。 -
GC 日志是调优的眼睛
生产环境必须开启 GC 日志轮转,并保留至少一周的历史。无论应用多健康,OOM 出现时若没有 Heap Dump 和 GC 日志,故障复盘将非常困难。 -
慎用
-XX:+UseCompressedOops等架构相关参数
在 64 位 JVM 中,压缩指针默认开启,能大幅降低内存占用。但若堆内存超过 32 GB,该参数会自动关闭,此时需要考虑改用更大的指针或减少堆内存。不要强行关闭,除非有充分的压测数据支持。
常见误区
-
误区1:JDK 11 还在用
-XX:PermSize
事实上,JDK 8 开始 PermGen 已被移除,该参数无效。面试时如果说 “我习惯把 PermSize 设为 256m”,会暴露知识停留在 JDK 7。 -
误区2:混淆
-Xmn与-XX:NewSize
两者功能类似,但-Xmn是-XX:NewSize与-XX:MaxNewSize的快捷方式,设-Xmn2g等效于将新生代初始与最大都设为 2g。建议新手统一使用-Xmn,简洁不易错。 -
误区3:过度依赖
-XX:+UseSerialGC
单机、小内存场景可用,但大型互联网应用如果还用 Serial GC,会让 GC 停顿长达数秒,这是严重缺乏调优意识的表现。
总结
JVM 启动参数是连接应用代码与运行时环境的配置桥梁。面试官通过你对参数的熟悉程度,快速判断你是否具备生产环境的实战经验。
掌握内存、GC、日志、故障排查四大类最常用参数,并清楚 JDK 11/17 相较于 JDK 8 的参数变更,是 Java 工程师进阶中高级的必经之路。