过程
- 只有HotSpot才有永久代。 BEA JRockit、IBM J9等来说,是不存在永久代的概念的。原则上如何实现方法区属于虛拟机实现细节,不受《Java虚拟机规范》管束,并不要求统一
- Hotspot中 方法区的变化:
- jdk1.6及之前:有永久代(permanent generation) ,静态变量存放在永久代上
- jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中
- jdk1.8及之后:无永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆
jdk6
jdk7
jdk8
永久代为什么要被元空间替换
- 随着Java8的到来HotSpot VM中再也见不到永久代了,但这并不意味着类的元数据信息也消失了。这些数据被移到了一个与堆不相连的本地内存区域,这个区域叫做元空间( Metaspace )
- 由于类的元数据分配在本地内存中,元空间的最大可分配空间就是系统可用内存空间
- 这项改动是很有必要的,原因有:
- 为永久代设置空间大小是很难确定的。 在某些场景下,如果动态加载类过多,容易产生Perm区的O0M。比如某个实际Web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误。
"Exception in thread' dubbo client x.x connector’java.lang.OutOfMemoryError: PermGenspace"
而元空间和永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制 - 对永久代进行调优是很困难的
- 为永久代设置空间大小是很难确定的。 在某些场景下,如果动态加载类过多,容易产生Perm区的O0M。比如某个实际Web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误。
StringTable 为什么要调整
jdk7中将StringTable放到了堆空间中。因为永久代的回收效率很低,在Full GC的时候才会触发,而Full GC 是老年代的空间不足、永久代不足时才会触发,这就导致了StringTable回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足,放到堆里,能及时回收内存