JVM内存结构升级至元空间需删除PermGen参数、设MaxMetaspaceSize、监控MU/MC指标,OOM日志应为“Metaspace”而非“PermGen”,并防范类加载器泄漏与本地内存耗尽。

JVM 内存结构发生改变时,平滑迁移的关键不是“实时切换”,而是提前适配新版本的行为逻辑,清理旧配置,验证运行态指标,并守住类加载器和本地内存这两条风险主线。
清理永久代参数,启用元空间管理
JDK 8+ 彻底移除永久代(PermGen),改由本地内存支撑的元空间(Metaspace)承载类元数据。若启动参数中仍保留 -XX:PermSize 或 -XX:MaxPermSize,JVM 会直接忽略并输出警告,这不仅无效,还可能掩盖真实配置问题:
- 必须删除所有 PermGen 相关 JVM 参数
- 设置 -XX:MaxMetaspaceSize=256m(根据实际类数量调整,如 Spring Boot 应用建议 384–512m)
- 保留 -XX:+CMSClassUnloadingEnabled 仍有效,但作用对象已变为元空间中的类加载器
监控指标要换语言,别再盯 PermGen
旧版用 jstat -gc 看 P 行(PermSize),新版需转向 MU(Metaspace used)和 MC(Metaspace capacity):
- 执行
jstat -gc <pid>,确认输出中无 P 列,有 MU/MC 列 - 用
jinfo -flag MaxMetaspaceSize <pid>检查是否生效(未设则返回 -1) - OOM 日志必须是 java.lang.OutOfMemoryError: Metaspace,而非 PermGen space
类加载器泄漏不会自动消失
元空间只是换了存储位置,不等于类能自动卸载。动态生成类(Spring CGLIB、Groovy、OSGi)仍会导致 ClassLoader 被长期持有:
- 定期执行
jmap -clstats <pid>,观察类加载器数量是否持续增长 - 用
jcmd <pid> VM.native_memory summary scale=MB查看 metaspace committed 值是否缓慢攀升 - 结合
jstack <pid>找出静态缓存、未注销监听器等强引用源
堆与元空间物理内存要分开压测
堆内存受 -Xmx 约束,而元空间使用本地内存,不受 JVM 堆限制——这意味着它可能悄悄吃光系统物理内存:
- 启动时加 -XX:NativeMemoryTracking=detail
- 运行中执行
jcmd <pid> VM.native_memory summary scale=MB,重点关注 committed 值 - 压力测试时分别观察老年代占用率与 metaspace committed 增长趋势,避免误判为“堆不够”而盲目扩堆

















