java.lang.OutOfMemoryError: Metaspace

场景说明

jdk8中把方法区实现移动到了元空间中,我们还原一次元空间溢出的场景:

import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes;
/**
 * 永久带内存溢出
 * -XX:MapPermSize=8m jdk1.6中
 * -verbose -XX:MaxMetaspaceSize=64m
 */
public class Jvm1_8 extends ClassLoader{
    public static void main(String[] args) {
        int j=0;
        try{
            Jvm1_8 test=new Jvm1_8();
            for (int i=0;i<200000000;j++,i++){
                ClassWriter cw=new ClassWriter(0);
                cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC,"Class"+i,null,"java/lang/Object",null);
                byte[] code=cw.toByteArray();
                test.defineClass("Class"+i,code,0,code.length);
            }
        }finally {
            System.out.println(j);
        }
    }
}

代码中内容是通过动态构造类的方式生成类,这样在很短的时间内产生大量的类,由于jdk8中元空间是存放在物理内存中,短时间看不出效果,我们加上参数-XX:MaxMetaspaceSize=64m限制元空间的大小。
运行效果如下:

92706
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:635)
	at Jvm1_8.main(Jvm1_8.java:18)

为了看到内部类信息的情况,我们加入-verbose参数可以显示看到类的加载情况:

 -verbose -XX:MaxMetaspaceSize=64m

输出如下:

[Loaded Class92695 from __JVM_DefineClass__]
[Loaded Class92696 from __JVM_DefineClass__]
[Loaded Class92697 from __JVM_DefineClass__]
[Loaded Class92698 from __JVM_DefineClass__]
[Loaded Class92699 from __JVM_DefineClass__]
[Loaded Class92700 from __JVM_DefineClass__]
[Loaded Class92701 from __JVM_DefineClass__]
[Loaded Class92702 from __JVM_DefineClass__]
[Loaded Class92703 from __JVM_DefineClass__]
[Loaded Class92704 from __JVM_DefineClass__]
[Loaded Class92705 from __JVM_DefineClass__]
92706
[Loaded java.lang.Throwable$PrintStreamOrWriter from /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Throwable$WrappedPrintStream from /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.util.IdentityHashMap from /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.util.IdentityHashMap$KeySet from /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Shutdown from /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Shutdown$Lock from /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar]
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:635)
	at Jvm1_8.main(Jvm1_8.java:17)

Process finished with exit code 1

后记

实际在很多框架中都是以动态生成类的方式去建立对象,在大量动态产生类的场景下,元空间消耗会增加,jdk8中这部分空间直接消耗物理内存,元空间消耗不是很明显察觉,可以适当减小元空间大小可以比较快看出元空间消耗的变化。

发布了48 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zhuxuemin1991/article/details/103935517