jvm gc参数必须以-xx:开头且在java命令中-jar或主类名之前指定,否则被忽略;不同jdk版本支持的gc选项不同,如jdk 8支持cms和g1,jdk 17+ zgc可直接启用,jdk 21+已移除cms;容器中需加-xx:+usecontainersupport并配合ram百分比参数避免oom。

必须用 -XX: 开头的参数在 java 命令启动时指定,运行中无法切换,也不存在“自动适配业务负载”的智能逻辑。
启动参数写在哪?顺序和位置有硬要求
JVM 启动参数中的 GC 选项(如 -XX:+UseG1GC)必须出现在 java 命令中 -jar 或主类名之前,否则会被忽略。JVM 只在初始化阶段读取并锁定 GC 实现,之后不会再解析。
- ✅ 正确:
java -XX:+UseZGC -Xms4g -Xmx4g -jar app.jar - ❌ 错误:
java -jar app.jar -XX:+UseZGC(参数被当成应用参数传给 main 方法) - ⚠️ 注意:多个
-XX:参数之间无顺序依赖,但若同时写了冲突参数(如-XX:+UseG1GC和-XX:+UseParallelGC),后出现的会覆盖前一个
不同 JDK 版本能用的参数不一样
不是所有 -XX:+UseXXXGC 都能在任意版本生效。参数有效性严格绑定 JDK 主版本和内部实现状态:
- JDK 8:支持
-XX:+UseParallelGC、-XX:+UseConcMarkSweepGC;-XX:+UseG1GC可用但非默认,需手动启用 - JDK 9–15:
-XX:+UseG1GC是默认,-XX:+UseZGC和-XX:+UseShenandoahGC需加-XX:+UnlockExperimentalVMOptions - JDK 17+:
-XX:+UnlockExperimentalVMOptions已废弃,-XX:+UseZGC直接可用(Linux/x64 平台) - JDK 21+:CMS(
-XX:+UseConcMarkSweepGC)已被彻底移除,尝试使用会报错Unrecognized VM option
容器环境不加 -XX:+UseContainerSupport 就容易选错
在 Docker/K8s 中,JVM 默认按宿主机内存判断该用哪个 GC——比如宿主机 64G、容器只分了 2G,JVM 却可能因“检测到大内存”而默认启用 G1,结果在小堆上跑出大量 Region 管理开销,反而卡顿。
- 务必显式加
-XX:+UseContainerSupport,让 JVM 读取cgroup内存限制 - 配合
-XX:InitialRAMPercentage、-XX:MaxRAMPercentage控制堆大小,避免堆占满容器内存触发 OOMKilled - 验证是否生效:启动后执行
jstat -gc $PID,看OC(老年代容量)是否接近你设的-Xmx,而不是远大于它
怎么确认实际生效的是哪个回收器?
别信文档,也别猜,直接看 JVM 自己说的:
- 启动时加
-XX:+PrintCommandLineFlags,输出里会明确带UseG1GC或UseZGC这类字样 - 加
-Xlog:gc*:stdout:time(JDK 10+)或-XX:+PrintGCDetails -XX:+PrintGCDateStamps(旧版),日志首行就有Using G1或Using Parallel - 运行中查:
jcmd $PID VM.native_memory summary | grep GC,或用jstat -gc $PID观察列名规律(如含G1、PS、ZGC字样)
最常被忽略的一点:GC 类型一旦启动就固定,哪怕你后续用 JMX 或 jcmd 调整了其他参数,也改不了收集器本身——换 GC 唯一办法是改参数、重启。











