outofmemoryerror: metaspace表明类元数据区耗尽,与堆内存无关;需先确认错误后缀为metaspace,再用jstat/jcmd/jconsole验证mu/mc占用,定位cglib代理、热部署等导致类加载器泄漏的源头,并设maxmetaspacesize等参数配合行为修复。

看到 OutOfMemoryError: Metaspace,说明类元数据区已耗尽,和堆内存完全无关。它不走常规 GC 流程,一旦超限就直接抛异常、中断线程甚至进程。排查核心不是加内存参数,而是定位“哪些类在疯狂加载却卸不掉”,再配合参数设限并修复加载行为本身。
第一步:确认确实是 Metaspace 问题
这是排查起点,必须严格核对错误日志末尾是否明确为 Metaspace(JDK 8+):
- 不是
Java heap space→ 调-Xmx没用 - 不是
Direct buffer memory→ 不用查 NIO 缓冲区 - 没有
PermGen字样 → 确认是 JDK 8 或更高版本
第二步:实时验证 Metaspace 是否真满
不能只信报错,要查实际占用。推荐以下轻量、无需重启的方式:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
jstat -gc <pid></pid>:重点看MU(已使用)和MC(当前容量)。若MU持续逼近或等于MC,且MC已达-XX:MaxMetaspaceSize设定值,基本可判定溢出 -
jcmd <pid> VM.native_memory summary</pid>:需启动时加-XX:NativeMemoryTracking=summary。输出中关注Class行的committed值,异常偏高是强信号 - JConsole 或 VisualVM 连上应用,直接查看
java.lang:type=MemoryPool,name=Metaspace的Usage.used值
第三步:定位高频加载又无法卸载的类源头
Metaspace 溢出本质是“类越积越多,卸不干净”。常见场景包括:
- Spring Boot DevTools 热部署反复启动,旧类加载器未回收
- CGLIB / ByteBuddy 动态代理(如 Spring AOP、Hibernate 延迟代理)生成大量匿名类
- Tomcat 部署多个 WAR 包,旧版本未彻底清理,类加载器残留
- 运行时编译 Groovy/Scala 脚本,每次执行都生成新类
- OSGi 或模块化系统频繁 install/uninstall bundle
临时加参数 -XX:+TraceClassLoading -XX:+TraceClassUnloading,观察日志中哪些类被反复加载却极少卸载,能快速圈定泄漏点。
第四步:参数配置与修复策略
参数只是辅助,核心是修正类加载行为本身:
- 生产环境必须设
-XX:MaxMetaspaceSize=256m(中小应用)或512m(Spring Cloud 微服务),防止吃光系统内存 - 搭配
-XX:MetaspaceSize=128m,控制首次触发 Metaspace GC 的阈值,兼顾启动性能和早期预警 - G1 GC 下启用
-XX:+UseG1GC,让 GC 尝试回收无用类元数据 - 慎用含字节码增强能力的第三方库;动态生成类逻辑务必做压力测试
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










