前两篇文章我们主要介绍的是java的堆内存溢出,这篇文章我们介绍下jvm的方法区内存溢出,也就是常见的Metaspace,完整报错示例如下:
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237) at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285) at com.oom.demo.OomDemo.Demo1.cglibCreate(Demo1.java:32) at com.oom.demo.OomDemo.Demo1.main(Demo1.java:20)
出现这种问题主要原因是方法区内存溢出了。首先我们介绍下jvm方法区的作用:
方法区((Method Area)与Java堆一样,是各个线程共享的内存区域。 方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误: java.lang.outOfMemoryError PermGen space或者java.lang. outOfMemoryError: Metaspace 加载大量的第三方的Jar包 Tomcat部署的工程太多 大量动态的生成反射类 关闭JVM就会释放这个区域的内存。
方法区的内存垃圾回收会在full gc的时候进行回收。下面我们演示+解决。
一、异常演示
验证本异常的完整代码如下:
package com.oom.demo.OomDemo; import java.util.ArrayList; import java.util.List; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; /** * * 元数据区内存溢出 * * jvm options: * -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC * -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=hprof/metadata-oom */ public class Demo1 { public static void main(String[] args) { cglibCreate(); } public static void cglibCreate() { int count = 0; while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Test.class); // 这里有个缓存设置 enhancer.setUseCache(false); enhancer.setCallback((MethodInterceptor)(o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects)); Test testProxy = (Test)enhancer.create(); System.out.println("当前创建了 " + (++count) + "个代理类"); } } static class Test { } }
这里是靠代理的方式使方法区发生内存溢出,在运行程序的时候,配置如下:
-Xms5g -Xmx5g -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
然后我们运行下,可以看到下面的异常日志
二、问题解决
一单我们看到Metaspace的时候,我们第一的印象一定要是知道是方法区出现了问题,与方法区相关的配置如下:
-XX:MetaspaceSize:Metaspace初始大小; -XX:MaxMetaspaceSize:Metaspace最大大小;
所以出现这种问题我们一般是增大一下这里的配置内存,同时还是检查下是否代码合理。
还没有评论,来说两句吧...