jvm05——方法区定义与内存溢出
5.1 定义
共享区域,主要存放类的组织结构(成员变量,方法、构造器的代码),常量池,类加载器。方法区在虚拟机启动时被创建。在逻辑上属于堆(具体产商实现时不一定划分在堆中)。在jdk1.8以前,方法区位于jvm的永久代,字符串存放在常量池。在jdk1.8以后,方法区则位于本地内存的元空间,字符串存在于堆。具体参考下图。
5.2 方法区内存溢出
通过下面代码可以演示方法区内存溢出。
public class Demo1_8 extends ClassLoader { // 可以用来加载类的二进制字节码 public static void main(String[] args) { int j = 0; try { Demo1_8 test = new Demo1_8(); for (int i = 0; i < 10000; i++, j++) { // ClassWriter 作用是生成类的二进制字节码 ClassWriter cw = new ClassWriter(0); // 版本号, public, 类名, 包名, 父类, 接口 cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null); // 返回 byte[] byte[] code = cw.toByteArray(); // 执行了类的加载 test.defineClass("Class" + i, code, 0, code.length); // Class 对象 } } finally { System.out.println(j); } } }
在jdk1.8以前的版本,将永久代设置为8m: -XX:MaxPermSize=10m
,在jdk1.8以后,将元空间设置为8m:-XX:MaxMetaspaceSize=8m
,将会报出OutOfMemoryError
.
在实际的工作场景中,spring、mybatis等框架都使用了cglib来动态生成class,因此框架使用不当是可能导致方法区内存溢出的。不过在jdk1.8以后方法区移到了元空间,空间充裕了很多,也由元空间进行垃圾回收,内存溢出的可能降低了。
java全栈日日学 文章被收录于专栏
java全栈每日必学,不要高估自己一年能做的事,不要低估自己十年能做的事