java -XX:+PrintCommandLineFlags -version 是最直接可靠的方式,可查看JVM实际启用的默认GC参数:JDK 8及以前默认Parallel GC(-XX:+UseParallelGC),JDK 9起(含11/17/21)默认G1(-XX:+UseG1GC),ZGC需显式启用且非默认;注意Docker环境可能受JAVA_TOOL_OPTIONS干扰。

用 java -XX:+PrintCommandLineFlags -version 直接看启动参数
这是最直接、最可靠的方式,不需要写代码或依赖运行时环境。JVM 启动时会自动打印它实际启用的默认 GC 参数。
-
-XX:+UseParallelGC表示用了 Parallel Scavenge + Parallel Old(JDK 8 及之前) -
-XX:+UseG1GC表示默认启用了 G1(JDK 9 起,包括 JDK 11/17/21) -
-XX:+UseZGC不会出现在默认输出里——ZGC 是实验性/显式启用的,哪怕在 JDK 21 也非默认 - 注意:JDK 21 的默认仍是
G1,不是 ZGC 或 Shenandoah;ZGC 要手动加-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
运行时查 ManagementFactory.getGarbageCollectorMXBeans()
适合已部署的应用,或者想在代码里做兼容性判断。但要注意:返回的是所有已注册的 GC Bean,不等于“当前活跃的默认 GC”——比如你没配 -XX:+UseG1GC,却看到 G1YoungGen 和 G1OldGen,那只是类加载器提前注册了,不代表它在工作。
- 真正有效的判断逻辑是:遍历
getGarbageCollectorMXBeans(),只取getName()中含"PS"(Parallel Scavenge)、"G1"或"Z"的,并结合isCollectionUsageThresholdSupported()等行为辅助确认 - 更稳妥的做法是配合 JVM 参数日志一起验证,单靠 MXBean 容易误判
- JDK 17+ 的
GarbageCollectorMXBean新增了getLastGcInfo(),能拿到最近一次 GC 的详细类型和耗时,比单纯看名字更准
别信文档,动手跑 java -version 对应的 JDK 实际版本
很多资料说“JDK 9+ 默认 G1”,但如果你用的是 OpenJDK 构建版(比如某些 Alpine Linux 镜像里的 openjdk:8-jre-slim),或打了定制 patch 的内部 JDK,它的默认 GC 可能被改过。
- 例如某些金融客户定制的 JDK 8,把默认 GC 改成了 CMS(虽然官方早已弃用)
- Docker 镜像中常见的
adoptium:11-jre-hotspot和eclipse-temurin:17-jre-jammy都严格遵循上游 OpenJDK 行为,即 JDK 11/17 默认G1 - 验证命令建议加
2>&1 | grep Use过滤,避免被其他输出干扰:java -XX:+PrintCommandLineFlags -version 2>&1 | grep Use
日志里看 GC 类型比看版本号更准
有些团队只记 JDK 大版本(比如“我们用 JDK 11”),但没注意具体构建号。而不同构建号对 GC 的默认行为可能有细微差别——尤其是早期 JDK 11 EA 版本曾短暂回退过 Parallel GC。
- 加
-Xlog:gc*:stdout:time(JDK 10+)或-XX:+PrintGCDetails(JDK 8)启动应用,观察第一行 GC 日志: - JDK 8 日志开头通常是
[GC (Allocation Failure) [PSYoungGen: - JDK 11+ 日志开头通常是
[GC pause (G1 Evacuation Pause) (young)或[GC concurrent-root-region-scan-end - 注意:G1 日志里出现
concurrent字样,基本可断定是 G1;Parallel GC 日志里几乎全是PS或ParNew前缀
JAVA_TOOL_OPTIONS 环境变量可能悄悄覆盖了默认 GC。比如某 K8s ConfigMap 里写了 JAVA_TOOL_OPTIONS=-XX:+UseParallelGC,那哪怕你用的是 JDK 17,也会强制走 Parallel GC。


















