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