JVM里的方法区是线程共享的内存区域,存储已被虚拟机加载的类信息、常量、静态变量,静态代码块、即时编译器(JIT Compiler)编译后的代码数据等。
简单而言,就是存储类结构信息,信息里包含了有常量池信息,加载到JVM之后就变成了运行时常量池。还有至于字符串常量池(串池)在jdk1.8之前和之后位置不同,1.8之前跟随运行时常量池在方法区,在1.8之后就独自在堆内存中了。
【重点】方法区是一个逻辑概念,其具体实现为jdk1.8的元空间与jdk1.8之前的永久代,他们之间最大的区别在于:元空间并不在JVM管理的内存中,而是使用本地内存。
替代的原因
1、1.8之前,字符串存在永久代中,容易出现性能问题和内存溢出,只有fullGC才会扫描清理到永久代,效率偏低。字符串常量
2、类及方法的信息等比较难确定其大小,放入系统内存更为合适
以1.8举例为例,我们在这里设置元空间大小为8m,且重复创建类,类的信息是放在方法区的,所以看看这里方法区的实现是什么。
设置大小-XX:MaxMetaspaceSize=8m
编写代码
public class HttpController extends ClassLoader {
public static void main(String[] args) throws Exception {
HttpController httpController = new HttpController();
for (int i = 0; i <100000; i++) {
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8,Opcodes.ACC_PUBLIC,"Class"+i,null,"java/lang/Object",null);
byte[] bytes = cw.toByteArray();
httpController.defineClass("Class"+i,bytes,0,bytes.length);
}
}
}
结果就是
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
内存溢出错误,这里是元空间Metaspace的内存溢出。这就证明了1.8的时候类的结构信息确实放在了元空间中。
【完,喜欢就点个赞呗】
正在去BAT的路上修行