场景说明
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中这部分空间直接消耗物理内存,元空间消耗不是很明显察觉,可以适当减小元空间大小可以比较快看出元空间消耗的变化。