JDK1.6到JDK1.8方法区的变化(大坑)

前言

来自小张的博客
JDK1.6到JDK1.8最明显的变化就是方法区的实现问题了,所以本章也是主要描述方法区的变化

从永久代到元空间

方法区(jdk7中实现为永久代,jdk8中为元空间),元空间并不在虚拟机中,而是使用本地内存,它和堆在逻辑上是连续的,但在物理上是不连续的,所以也叫非堆。

题外话 方法区与堆是线程间共享的
上图
JDK1.6到JDK1.8方法区的变化(大坑)_第1张图片
可见方法区分为类的信息、常量池、方法数据、方法代码

变化

JDK版本 方法区实现 变化
jdk1.6 永久代 字符串常量池、运行时常量池、静态变量都是在永久代中
jdk1.7 永久代 字符串常量池和静态变量被移动到了堆当中,运行时常量池还是在永久代中
jdk1.8 元空间 字符串常量池和静态变量仍然在堆当中;运行时常量池、类型信息、常量、字段、方法被移动都了元空间中

JDK1.7时并没有完全取消永久代,而是采用永久代+堆的形式,直到jdk1.8才正式取消永久代使用元空间实现方法区。

大坑

注意:jdk1.7时将字符串常量池与静态变量移入堆之后,在jdk1.8元空间时并没有将其移到元空间,还是将其继续留在了堆空间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fh9jlhhI-1668340975114)(https://zwnblog.oss-cn-shenzhen.aliyuncs.com/halo/第08章_方法区的演进细节-hotspot.jpg)]

PermGen(永久代)

PermGen , 就是 PermGen space ,全称是 Permanent Generation space ,是指内存的永久保存区域。
PermGen space 是JDK7及之前, HotSpot虚拟机基于JVM规范对方法区的一个落地实现。在JDK8被移除。

Metaspace(元空间、JDK8及之后):

元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。
移除PermGen(永久代)从从JDK7 就开始。例如,字符串内部池,已经在JDK7 中从永久代中移除。直到JDK8 的发布将宣告 PermGen(永久代)的终结。
元空间则是JDK1.8及之后,HotSpot虚拟机对方法区的新实现。

为什么使用元空间替换永久代?

通过上面分析,大家应该大致了解了 JVM 的内存划分,也清楚了 JDK8 中永久代 向 元空间的转换。不过大家应该都有一个疑问,就是为什么要做这个转换?所以,最后给大家总结以下几点原因:

  • 表面上看是为了避免OOM异常。
  • 因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。
  • 当使用元空间时,可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制。
  • 更深层的原因还是要合并HotSpot和JRockit的代码,JRockit从来没有所谓的永久代,也不需要开发运维人员设置永久代的大小,但是运行良好。同时也不用担心运行性能问题了,在覆盖到的测试中, 程序启动和运行速度降低不超过1%,但是这点性能损失换来了更大的安全保障。

总结

  • 1)字符串存在永久代中,容易出现性能问题和内存溢出。
  • 2)类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。
  • 3)永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。

你可能感兴趣的:(jvm,java,开发语言)