java -XX:+PrintFlagsFinal 输出中带 {default} 标记的参数是 JVM 运行时自动推导值(如基于 cgroup 限制计算的堆大小),{product} 表示 JDK 编译期内置默认值,无标记项则表明该参数被命令行显式设置;最可靠确认方式是检查 ps aux | grep java 或 jcmd VM.flags 查看实际启动参数。

OpenJDK 本身不记录“哪些参数是默认的、哪些是用户手动设置的”,它只按最终生效的 JVM 参数运行。区分的关键不在 JVM 运行时,而在启动过程和参数来源的可追溯性。
怎么看 java -XX:+PrintFlagsFinal 输出里哪些是默认值
java -XX:+PrintFlagsFinal 会列出所有 JVM 参数的最终值,并在每行末尾标注 {default}、{product}、{manageable} 等标记。其中:
-
{default}表示该值由 JVM 内部逻辑推导得出(比如未显式设-Xmx时,JVM 根据物理内存或容器 cgroup limits 自动算出堆上限),不是硬编码的静态默认值 -
{product}表示这是 JDK 发行版内置的编译期默认值(如UseParallelGC在 JDK8 中默认为 true) -
{managed}或{diagnostic}等表示该参数支持运行时动态修改,与是否手动设置无关 - 没有标记的项,通常意味着它被命令行明确设置了(例如你写了
-Xms512m,对应行就不会带{default})
容器环境下 -Xmx 不写也会有值,这算“默认”还是“自动推导”
从 OpenJDK 8u191 开始,只要运行在 Linux cgroup v1/v2 环境中(即 Docker/Kubernetes 容器),JVM 会主动读取 /sys/fs/cgroup/memory.max(v2)或 /sys/fs/cgroup/memory/memory.limit_in_bytes(v1)来计算堆大小上限,这个行为由 -XX:+UseContainerSupport 控制(JDK8u191+ 默认开启)。
- 即使你没写
-Xmx,PrintFlagsFinal里MaxHeapSize的值仍会带{default}—— 因为它是运行时根据 cgroup 动态算出来的,不是编译时写死的 - 如果你显式写了
-Xmx2g,那MaxHeapSize行就不再标{default},且值固定为 2147483648 - 注意:OpenJDK 8u222 及以后版本,
os::physical_memory()方法内部已直接集成 cgroup 检测逻辑,无需额外开关
怎么确认某参数到底是不是你写的
最可靠的方式是检查 JVM 启动命令本身,而不是依赖运行时状态:
- 用
ps aux | grep java查看完整启动命令,过滤掉-D、-X、-XX开头的参数 - 在容器中,检查
Dockerfile的ENTRYPOINT或CMD,以及docker run命令末尾传入的参数 - 如果用了
JAVA_OPTS环境变量,务必注意:它是否被启动脚本实际拼接到 java 命令中(有些 shell 脚本会忽略空值或做条件判断) -
jcmd可以看到当前 JVM 实际解析后的全部非默认参数(即显式设置的那些),但不包含VM.flags {default}类型的推导值
真正容易被忽略的是:cgroup 推导行为不可见于启动命令,却实实在在覆盖了你的预期。哪怕你什么都没配,JVM 也可能把 MaxHeapSize 设成 256MB(因为容器限制是 1GB)。这种“静默生效”的机制,比手误漏写参数更难排查。











