java6->java7->java8的内存結構的演變
在java7及以前,物理上来说,它们是连续的一块内存,逻辑上依旧是分开的。对于习惯了在HotSpot虚拟机上开发、部署的程序员来说,很多都愿意将方法区称作永久代。
Java7中永久代中存储的部分数据已经开始转移到堆或本地方法區中了。比如,符号引用转移到了本地方法區;字符串常量池转移到了堆;类的静态变量转移到了堆。
java8中Hotspot取消了永久代,永久代的参数 -XX:PermSize
和-XX:MaxPermSize
也随之失效。在Java8中,元空间登上舞台,方法区存在于元空间。同时,元空间不再与堆连续,而且是存在于本地内存。
元空间
元空间存在于本地内存,意味着只要本地内存足够,它不会出现像永久代中“java.lang.OutOfMemoryError: PermGen space”这种错误。看上图中的方法区,是不是“膨胀”了。
本地内存,也称为 C-Heap,是供JVM自身进程使用的。当Java Heap空间不足时会触发GC,但Native memory空间不够却不会触发GC。
默认情况下元空间是可以无限使用本地内存的,但为了不让它如此膨胀,JVM同样提供了参数来限制它使用的使用。
-XX:MetaspaceSize
,class metadata的初始空间配额,以bytes为单位,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当的降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize(如果设置了的话),适当的提高该值。-XX:MaxMetaspaceSize
,可以为class metadata分配的最大空间。默认是没有限制的。-XX:MinMetaspaceFreeRatio
,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为class metadata分配空间导致的垃圾收集。-XX:MaxMetaspaceFreeRatio
,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为class metadata释放空间导致的垃圾收集。
永久代为什么被替换了
- 字符串存在永久代中,容易出现性能问题和内存溢出
- 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出
- 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低
- 将 HotSpot 与 JRockit 合二为一