是java.lang.outofmemoryerror: metaspace,主因是-xx:maxmetaspacesize设置过小或类加载异常导致元空间耗尽,需结合gc日志、jstat、jcmd等工具分析类加载行为并调优参数。

直接看日志里报的错是不是 java.lang.OutOfMemoryError: Metaspace。如果是,基本就是元空间不够用了,和 -XX:MaxMetaspaceSize 设置太小强相关。
确认元空间是否真被耗尽
不能光看 OOM 报错就下结论。先检查 JVM 启动参数里有没有显式设置 -XX:MaxMetaspaceSize,以及设了多少。再查 GC 日志(需开启 -XX:+PrintGCDetails),重点关注类似这样的记录:
- Metaspace used=248765K, committed=251904K, reserved=1230848K
- GC 日志中出现
Metadata GC Threshold或Metaspace GC的触发记录
如果 committed 值无限逼近甚至等于 MaxMetaspaceSize,且频繁触发 Metaspace GC,说明上限确实卡死了。
分析类加载行为是否异常
元空间存的是类的元数据(Class 对象、方法签名、常量池等),不是类实例。所以问题往往出在“加载了太多类”,而不是对象太多。常见诱因有:
- 大量使用反射 + 动态代理(如 Spring AOP 在切面多时会生成大量代理类)
- 频繁热部署或类重载(比如 DevTools、JRebel 在生产误用)
- 引入了含巨量内部类/匿名类的第三方 SDK(某些老版本 Jackson、Hibernate 插件有此问题)
- 自定义 ClassLoader 未正确卸载,导致类泄漏(尤其在模块化或插件化场景)
可用 jstat -gc <pid></pid> 实时观察 M (Metaspace) 使用趋势;或用 jcmd <pid> VM.native_memory summary scale=MB</pid> 查看原生内存中 metaspace 分配总量。
安全调整与长期治理
临时缓解可适当调高 -XX:MaxMetaspaceSize,但必须同步做根因分析,否则只是掩盖问题:
- 建议搭配 -XX:MetaspaceSize(初始大小)一起设,避免启动初期频繁扩容(如 -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m)
- 开启元空间详细日志:-XX:+TraceClassLoading -XX:+TraceClassUnloading(仅调试期用,性能开销大)
- 用 jmap -clstats
查看各 ClassLoader 加载类数量,定位“加载狂魔” - 生产环境禁用任何热重载机制;AOP 切面尽量收敛,避免通配符过度匹配
不复杂但容易忽略。










