面试题剖析:GC中对象什么时候会从新生代进入老年代

文章详细介绍了在Java垃圾回收机制中,对象如何从新生代进入老年代的四种情况:1) 年龄超过15次;2) 大对象直接进入;3) Young GC后存活对象超出Survivor区大小;4) Survivor区非本次GC对象超过一半。同时讨论了老年代空间分配担保策略,确保系统稳定运行。
摘要由CSDN通过智能技术生成

面试题:假设我们使用普通的垃圾回收器,新生代用ParNew 、老年代使用ConcMarkSweep (即CMS),发生GC的时候,成为垃圾的对象什么时候会从新生代转移到老年代?

面试题常规回答

有的面试者可能会回答:新对象的产生是先在新生代的Eden区分配内存,当Eden区的内存容量满了之后,进行Young GC的时候,ParNew垃圾回收器会采用复制清理算法将Eden剩下的存活对象全部复制到其中一个Survivor区,假设为Survivor1区,然后把Eden区清空掉,供新对象分配内存。接下来,Eden区再次满了之后,ParNew会再次将Eden区和Survivor1区中存活的对象全部复制到Survivor2区中,然后再清理。如此循环往复地将存活对象在Survivor1区和Survivor2区来回转移,等到对象的年龄超过了15次(每次垃圾回收都是增加1次年龄),再将存活对象放入老年代。
Young GC的垃圾回收机制

另外一种情况就是大对象超过了指定阈值(默认1M),直接放入老年代。

上面两种情况是经常被提到的回答,当实际上还有两种情况是我在面试过程中几乎没听过的,接下来我们分析一下剩下的两种情况:

Young GC后,存活对象太多也进入老年代

如果ParNew进行Young GC后,发现存活的对象都超过了Survivor区的大小,这时候会直接将全部存活对象转移到老年代。

这里涉及到一个JVM的调优,如果经常出现每次在Young GC后都把大量的存活对象转移到老年代,那么老年代也会很快就进行Old GC,这个过程将会很漫长,还会发生Stop The World,用户看起来就是系统老是一卡一卡的,体验特别差。

这时候就需要考虑一下加大Survivor区的大小了,涉及的参数如下:

-Xms4096M -Xmx4096M -Xmn1024M -XX:SurvivorRatio=8

解释一下参数的意义:

-Xms4096M -Xmx4096M 这两个就是JVM整个堆的最小和最大内存容量4G,一般两个值都设为一样。

-Xmn1024M 表示新生代可用的内存容量,包括Eden+2个Survivor区。

-XX:SurvivorRatio=8 表示新生代中Eden区的比例,这里表示Eden区占80%的内存容量,剩下2个Survivor区各占10%。

动态年龄判断规则:Survivor区中非本次GC的对象都超过了容量的一半,全部进入老年代

还有一种比较少听到的情况,就是当这次Young GC中,发现当前Survivor区中,其他剩余的存活对象的内存大小已经超过了Survivor区容量的一半时,ParNew会直接将这些对象全部转移到了老年代的堆里面。这是因为垃圾回收器认为,如果对象经常需要存活,那么就应该直接进入老年代中,作为常用对象被使用。

举个例子,假设Survivor区中,年龄3及以上的对象占30%,年龄2的对象占20%,那么这时候就会将年龄2+年龄3及以上的对象全部放入老年代,年龄1会继续转移到另一个Survivor区。

再举另外一个例子,年龄4及以上的对象占40%,年龄3的对象占10%,那么年龄3+年龄4及以上的对象全部放入老年代,年龄2及以下对象会继续转移到另一个Survivor区。

其实这最后一种情况才是最经常发生的,新生代对象转移到老年代。

老年代空间分配担保

首先,在执行任何一次Young GC之前,JVM会先检查一下老年代可用的可用内存空间,是否大于新生代所有对象的总大小

  1. 如果老年代可用的可用内存空间>新生代内存空间,此时就可以放心大胆的对新生代发起一次Young GC了,因为即使Young GC之后所有对象都存活,Survivor区放不下了,也可以转移到老年代去。

  2. 如果发现老年代可用内存空间<新生代内存空间,这个时候就会进一步判断,内存空间是否大于之前每一次Young GC后进入老年代的对象的平均大小。

举个例子,之前每次Young GC后,平均都有20MB左右的对象会进入老年代,如果此时老年代可用内存大于20MB。这就说明,很可能这次Young GC过后也会差不多有20MB左右的对象会进入老年代,此时老年代空间是够的。所以这个时候也是允许尝试进行Young GC的。

如果尝试Young GC过后,剩余的存活对象的大小,大于了Survivor区域的大小,也大于了老年代可用内存的空间大小。也就是说此时老年代都放不下这些存活对象了,就会发生Handle Promotion Failure的情况(空间分配担保失败),这个时候就会触发一次Full GC。

Full GC会同时回收新生代和老年代的内存空间,如果Full GC之后,发现老年代的可用内存空间还是放不下存活的对象,那么JVM就只能内存溢出了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Gemini技术窝

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

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

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

打赏作者

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

抵扣说明:

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

余额充值