堆,方法区,永久代,元空间 之间的关系
-
方法区和永久代的关系
方法区是 《Java虚拟机规范 》中的规范,在 HotSpot 虚拟机中,JDK 6.0 及以前由永久代实现,就如同 Java 中的接口和实现一样。
永久代并不是很好的方法区实现,《Java虚拟机规范》中方法区不需要连续的内存并且可以选择固定大小或可扩展,而永久代有
-XX:MaxPermSize
上限,即使不设置也有默认大小,很容易造成内存溢出。 -
堆和方法区的关系
《Java虚拟机规范》把方法区描述为堆的逻辑部分,但它却有一个名字 Non-Heap 非堆,两者物理上并无联系。
两者的共同点就是都可以选择固定大小或可扩展。
-
元空间:JDK 8 把永久代迁移到由本地内存实现的元空间当中
-
永久代数据迁移
- 1.6 及以前永久代是方法区的实现,其中包括:已加载的类型信息,常量,静态变量,即时编译器编译过后的代码缓存等。
- 1.7 将字符串常量池,静态变量移出到堆中。
- 1.8 将老年代剩余内容(主要是类型信息)全部移到元空间中。
-
方法区的实现永久代真的永久吗?
垃圾回收在这个区域出现的比较少,但是并不是没有,主要是常量池的回收和类型的卸载。主要是动态类的生成:CGLib字节码增强,JSP 等。
-
永久代和元空间
JDK 8 以后,永久代完全退出历史舞台,由元空间替代
-
常量池在 JDK 6,7,8 中存在位置证明
import java.util.HashSet; import java.util.Set; public class RuntimeConstantPoolOOM { public static void main(String[] args) { Set<String> set = new HashSet<>(); int i = 0; while (true){ // String.intern();去字符串常量池中查找有没有这个字符串,有的话指向引用,没有将字符串拷贝进字符串常量池当中 set.add(String.valueOf(i++).intern()); } } }
- JDK 6:
-XX:MaxPermSize
限制永久代大小,异常OOM:PermGen space
,代表永久代空间不足,此时字符串常量池在永久代当中。 - JDK 7及以上:
-XX:MaxPermSize
限制永久代大小,循环一直下去,不会爆异常。-Xmx
限制最大堆就可以看到OOM:heap space
堆内存不足,代表字符串常量池在堆中。
- JDK 6: