jvm堆空间划分_jvm内存模型和内存结构

jvm堆空间划分_jvm内存模型和内存结构JavaJVM堆内存的GC模型以及分代机制,包括堆空间GC分区,对象晋升,GC触发策略等

Java堆从GC的角度还可以细分为: 年轻代(Young)、老年代(Tenured )和永久代(Perm,jdk1.7以及之前的堆空间逻辑分区,区别堆空间)。

1 JDK1.7的堆内存GC模型

在这里插入图片描述

1.1 Young 年轻代

Young中的大部分对象的生命都是短暂的,所以将内存分为一块较大的Eden和两块较小的大小严格相同的Survivor1、Survivor2,JVM默认分配是8:1:1(但是JVM默认开启Survivor区大小自动变化的参数,关闭即可。),其中,Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用。每次调用Eden和其中的Survivor1(FromSpace)。

在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。在Eden区间变满的时候,触发Minor GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

1.2 Tenured 老年代

Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后(Minor GC),对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。

同理,当老年代中没有足够的内存空间来存放对象时,虚拟机会发起一次Major GC/Full GC。其实不论是Minor GC或者Major GC都存在这么一个问题,怎么处理跨代引用?因此通常Major都会回收年轻带。

Serial,Parallel scavenge,Parallel old垃圾回收器回收老年代的时候还会回收年轻代,Major GC就是Full GC。

CMS则是有两种模式,在没有设置-XX:+CMSScavengeBeforeRemark的时候,会扫描年轻代,但是只回收老年代,只有这个模式是真正的只进行Old GC;设置之后,会同时回收老年代和年轻。

G1比较特殊,它无论处于何种模式下,都不需要扫描别的代,只需要处理一下记忆集;

1.3 Perm 永久代

Perm Gen代主要保存class,method,filed对象,这部份的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。

2 JDK1.8的堆内存模型

在这里插入图片描述

由上图可以看出,JDK1.8的堆内存模型是由2部分组成,年轻代 + 年老代。

年轻代:Eden + 2*Survivor
年老代:Old Gen

在JDK1.8中变化最大的Perm区,用Metaspace(元数据空间)进行了替换。需要特别说明的是:Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存空间中,这也是与1.7的永久代最大的区别所在。至于为什么废除永久代,在前面jvm内存模型中有讲解:JDK1.7和1.8的JVM运行时数据区域(JVM内存模型)的主要区别。

3 堆空间的GC

针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种:

  1. Partial GC:并不收集整个GC堆的模式
    1. Young GC:只收集Young Gen的GC,又称Minor GC。
    2. Old GC:只收集Old Gen的GC,又称Major GC。但是只有CMS的concurrent collection是这个模式,其他垃圾收集器所谓的Old GC在回收老年代的时候还会回收年轻代,因此Old GC常常和Full GC是等价的。
    3. Mixed GC:收集整个Young Gen以及部分Old Gen的GC。只有G1垃圾收集器有这个模式。
  2. Full GC:收集整个堆,包括Young Gen、Old Gen、Perm Gen(如果存在的话)等所有部分的模式。

3.1 Young GC & Minor GC

3.1.1 触发条件

当年轻代(Eden区)满时就会触发,这里的年轻代满指的是 Eden区满。Survivor 满不会引发 GC,而是移动到老年代。Young GC中有部分存活对象会晋升到Old gen,所以Young GC后Old gen的占用量通常会有所升高。

执行Minor GC操作时,不会影响到永久代。从永久代到年轻代的引用被当成GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉。

3.1.2 GC策略

复制算法:

  1. 在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。
  2. 紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”;而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域;复制到“TO”区域的对象“年龄”+1。大对象则可能被直接移动到老年代中,这是防频繁的复制带来的开销过大。
  3. 经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。
  4. GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

3.2 Old GC & Major GC & Full GC

这些术语无论是在 JVM 规范,还是在垃圾收集研究论文中都没有正式的定义,甚至国内国外的常见叫法也不一样。

Major GC通常是跟Full GC是等价的,除了CMS的concurrent collection之外,其它能收集Old Gen的GC都会同时收集整个GC堆,包括Young Gen。

Full GC 一般消耗的时间比较长,远远大于Minor GC,因此,有时候我们必须降低FullGC 发生的频率。在最近几个版本的JDK里默认包括了对永久代即方法区的回收(JDK8中无永久代了)。

3.1.1 触发条件

  1. 在Minor GC之前每次晋升的对象的平均大小 > 老年代剩余空间
    当准备要触发一次Young GC时,如果发现统计数据说之前Young GC的平均晋升大小比目前Old gen剩余的空间大,则不会触发Young GC而是转为触发Full GC(因为HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集Old Gen的GC都会同时收集整个GC堆,包括Young Gen,所以不需要事先触发一次单独的Young GC)。
  2. Minor GC之后存活的对象超过了老年代剩余空间。
    以上这两种情况都是因为老年代会为新生代对象的晋升提供担保,而每次晋升的对象的大小是无法预测的,所以只能基于统计,1个是基于历史平均水平,一个是基于下一次可能要晋升的最大水平。
    这两种情况都会引起Full GC,这种情况下会使用Serial Old收集器,是单线程的,对GC的影响很大。
  3. System.gc():系统建议执行Full GC,但是不一定会执行 。
    可以设置-XX:+ DisableExplicitGC来禁止调用System.gc引发Full GC。
  4. 永久代(方法区)空间不足
    如果有Perm Gen的话,要在Perm Gen分配空间但已经没有足够空间时,也要触发一次Full GC。避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。
  5. Minor GC使得有新生代的对象晋身入老年代,导致老年代空间不够用时触发。

3.1.2 GC策略

标记清除法/标记整理法:

老年代与年轻代不同,老年代对象存活的时间比较长、比较稳定,因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,回收后对用空出的空间要么进行合并、要么标记出来便于下次进行分配,总之目的就是要减少内存碎片带来的效率损耗。这两种方法具体哪种要看具体的垃圾收集器的实现。当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。

相关文章

  1. R大博客

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

今天的文章jvm堆空间划分_jvm内存模型和内存结构分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/88701.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注