升级openjdk后需用jcmd vm.native_memory summary比对class、code、internal三区变化,结合jstat -gc观察老年代回收效率及-xlog:gc日志时间戳稳定性,重点核查-xx:maxmetaspacesize和-xx:maxdirectmemorysize是否显式配置。

升级 OpenJDK 后怎么确认内存占用没变差
直接看 ps 或任务管理器里的 RSS 值没用——它混了堆、元空间、线程栈、直接内存、JIT 代码等所有本地内存。升级 JDK 后真正要盯的是 JVM 内部各区域的分配与使用效率是否退化。
jcmd VM.native_memory summary 是第一道筛子
OpenJDK 8u60+ 默认支持 NMT(Native Memory Tracking),升级后必须立刻验证它是否生效,这是唯一能区分“是堆涨了”还是“是 JVM 自身吃多了”的手段。
- 先启用 NMT(如果还没加):启动时加
-XX:NativeMemoryTracking=summary(生产环境够用,detail会拖慢启动且日志巨大) - 运行中检查:
jcmd <pid> VM.native_memory summary scale=MB</pid> - 重点比对升级前后三块:
Class(类元数据)、Code(JIT 编译代码)、Internal(JVM 内部结构)。JDK 17/21 的 ZGC/G1 在这些区域通常更省,若反而涨了 30%+,说明可能触发了已知 bug 或配置不兼容
对比 jstat -gc 输出的 Old 区回收效率
JDK 升级常伴随 GC 策略默认变更(比如从 Parallel 切到 G1),光看堆大小没意义,要看老年代是否“清得动”。
- 执行:
jstat -gc <pid> 2000 5</pid>(每 2 秒打一次,共 5 次) - 关键列:
OU(Old Used)、OC(Old Capacity)、YGCT/FGCT(Young/Full GC 耗时) - 异常信号:
OU持续逼近OC且FGCT明显变长(比如从 50ms → 200ms),或出现promotion failed(G1)/concurrent mode failure(CMS)——这往往不是代码问题,而是新 JDK 的 GC 参数与旧应用节奏不匹配
别跳过 -Xlog:gc 的时间戳对齐检查
新版 JDK(9+)强制用 -Xlog,但很多人只加参数没验证日志是否真在写。升级后 GC 行为变化可能藏在毫秒级时间偏移里。
- 确保启动参数含:
-Xlog:gc*:file=gc.log:time,uptime,pid,tags,level - 查日志头几行,确认
uptime和系统时间差是否稳定(如始终差 12.3s 可接受,忽大忽小说明日志采样抖动) - 用
grep "Full GC\|promotion failed" gc.log | head -10快速扫首屏——升级后首次 Full GC 若发生在 5 分钟内且回收量<10%,大概率是元空间或直接内存配置未同步调整
最易被忽略的点:JDK 升级后,-XX:MaxMetaspaceSize 和 -XX:MaxDirectMemorySize 不再继承旧值,如果没显式设置,新版本可能用更大默认值;而 libnet.so 或 libnio.so 的本地缓冲区行为也可能因 JNI 层变更而膨胀。NMT 报告里 Internal 或 Other 栏突然变厚,八成在这两处。











