Java JVM的堆内存的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学习博客!

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值