目录
首先声明,只有 HotSpot 才有永久代
BEA JRockit、IBM J9 等来说,是不存在永久代的概念的。原则上如何实现方法区属于虚拟机实现细节,不受《Java 虚拟机规范》管束,并不要求统一
随着 Java8 的到来,HotSpot VM 中再也见不到永久代了。但是这并不意味着类的元数据信息也消失了。这些数据被移到了一个与堆不相连的本地内存区域,这个区域叫做元空间(Metaspace)
由于类的元数据分配在本地内存中,元空间的最大可分配空间就是系统可用内存空间
这项改动是很有必要的,因为:
1. 为永久代设置空间大小是很难确定的
在某些场景下,如果动态加载类过多,容易产生 Perm 区的 OOM。比如某个实际 Web 工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误
而元空间和永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制
2. 对永久代进行调优是很困难的
jdk7 中将 StringTable 放到了堆空间中。因为永久代的回收效率很低,在 Full GC 的时候才会触发。而 Full GC 是老年代的空间不足、永久代不足时才会触发
这就导致 StringTable 回收效率不是很高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存
方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型
HotSpot 虚拟机对常量池的回收策略是很明显的,只要常量池中的常量没有被任何地方引用,就可以被回收
不过方法区的回收效果比较难令人满意,尤其是类型的卸载,条件相当苛刻