方法区溢出与堆内存溢出本质不同:堆溢出提示“Java heap space”,因对象过多无法回收;方法区溢出(JDK8+)提示“Metaspace”,因类加载过多无法卸载;二者诱因、参数(-Xmx vs -XX:MaxMetaspaceSize)、监控指标(OU vs MC)及Dump分析重点均截然不同。

方法区溢出和堆内存溢出虽然都表现为 OutOfMemoryError,但错误提示、触发场景、排查路径和解决思路有本质区别。关键不是“哪个更严重”,而是“哪块区域先扛不住”——这直接指向代码或配置的薄弱点。
错误提示明显不同
这是最直观的区分依据:
-
堆内存溢出:异常信息明确带
java.lang.OutOfMemoryError: Java heap space -
方法区溢出(JDK 8+):提示为
java.lang.OutOfMemoryError: Metaspace;JDK 7 及之前则是java.lang.OutOfMemoryError: PermGen space
典型诱因逻辑相反
堆溢出是“对象太多活不掉”,方法区溢出是“类太多卸不掉”:
- 堆溢出常见原因:大量短生命周期对象堆积(如循环创建大数组)、长生命周期对象持有强引用(如缓存未清理)、内存泄漏(如静态集合不断add)
- 方法区溢出常见原因:频繁动态生成类(如CGLIB代理、JSON序列化框架反复生成类)、大量JSP编译、OSGi容器中类加载器未释放、热部署时旧类加载器残留
JVM参数与监控指标差异大
调优和观察不能套用同一套参数:
-
堆相关参数:-Xms、-Xmx 控制初始/最大堆大小;可通过
jstat -gc观察OU(老年代使用量)持续增长或 GC 频繁失败 -
方法区相关参数:JDK 8+ 用
-XX:MetaspaceSize和-XX:MaxMetaspaceSize;JDK 7 用-XX:PermSize和-XX:MaxPermSize;jstat -class中MC(已加载类数量)持续上升且CCSC(压缩类空间容量)接近上限,是典型信号
Dump分析重点完全不同
拿到 heap dump 后,分析方向截然不同:
- 堆溢出 dump:用 MAT 或 VisualVM 查看 Dominator Tree,找占用内存 Top 的对象类型;再通过 Histogram + Path to GC Roots 找出谁在强引用它们
-
方法区溢出 dump:需用
jcmd <pid> VM.native_memory summary或jstat -class辅助判断;dump 中重点不是对象实例,而是ClassLoader实例数量、重复加载的类名(如大量 $$_EnhancerByCGLIB$$ 类)、以及各 ClassLoader 加载的类数是否异常膨胀

















