jvm默认gc由版本和硬件决定:jdk 8默认parallel,jdk 9+默认g1,jdk 21仍默认g1但支持zgc手动启用;启动后不可自动切换,须显式参数指定。

JVM 垃圾回收器(GC)的自动选择不是靠“智能判断”,而是由 JVM 版本 + 运行时硬件环境 + 默认策略 共同决定的,不依赖应用代码或配置。从 JDK 8 到 JDK 21,不同版本默认启用的 GC 收集器已发生明显变化,且会根据 CPU 核心数、可用内存等参数动态适配。
JVM 自动选 GC 的关键依据
-
JDK 版本是首要决定因素
不同 JDK 版本内置了不同的默认 GC 策略:- JDK 7u4 以前:Serial(单线程,客户端模式)
- JDK 8:Parallel(吞吐量优先,默认服务端模式)
- JDK 9 起:G1 成为默认 GC
- JDK 17(LTS)及之后:G1 仍为默认,但 ZGC 和 Shenandoah 已稳定支持
- JDK 21(LTS):G1 仍是默认,但启动时若满足条件(如
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC),可手动启用 ZGC;自动启用仍需显式指定
-
运行时硬件特征触发隐式调整
JVM 启动时会探测以下信息,并可能覆盖部分默认行为:- CPU 核心数 ≥ 2 且内存 ≥ 2GB → 默认启用并行 GC(JDK 8)或 G1(JDK 9+)
- 内存 ≤ 128MB 或 CPU = 1 → 可能回退到 Serial GC(尤其在容器资源受限时)
- 使用容器(Docker/K8s)且未设
-XX:+UseContainerSupport→ 可能误判可用内存,导致 GC 选型失当(例如本应选 G1 却用了 Parallel)
-
没有“运行中动态切换 GC”的自动机制
JVM 在启动阶段完成 GC 初始化后,整个生命周期内不会自动更换收集器。所谓“自适应”是指:- G1 内部会动态调整 Region 回收顺序和并发线程数
- ZGC/Shenandoah 在运行时调节并发标记/转移节奏
- 但 Serial → Parallel → G1 → ZGC 这类跨收集器切换,必须重启 JVM 并显式指定参数(如
-XX:+UseZGC)
如何确认当前使用的 GC
运行时可通过以下方式验证实际生效的 GC:
-
java -XX:+PrintCommandLineFlags -version
输出类似-XX:+UseG1GC,表明启动时已自动启用 G1 -
jstat -gc <pid></pid>
查看S0C,S1C,EC,OC,MC等列,结合命名规律识别(如 G1 对应GU/GC列含G1字样) - JMX 或
jcmd <pid> VM.native_memory summary</pid>中的 GC 相关字段 - 应用启动日志中搜索
Using关键字,例如:Using G1或Using Parallel GC
建议:别依赖自动选择,而要主动控制
- 生产环境务必显式指定 GC(如
-XX:+UseG1GC或-XX:+UseZGC),避免因 JDK 升级或部署环境差异导致 GC 行为突变 - 容器环境中,必须加
-XX:+UseContainerSupport,并配合-XX:InitialRAMPercentage等参数,否则 JVM 可能按宿主机内存选 GC,造成小内存容器触发大堆 GC 策略 - 高吞吐场景(批处理)→ Parallel GC
- 低延迟敏感(API 服务、实时交易)→ G1(停顿可控)或 ZGC(
- 超大堆(>64GB)且延迟严苛 → ZGC 或 Shenandoah 更合适
不复杂但容易忽略











