017、大厂面试题:年轻代和老年代分别适合什么样的垃圾回收算法?

年轻代和老年代分别适合什么样的垃圾回收算法?
目录:
前文回顾
躲过15次GC之后进入老年代
动态对象年龄判断
大对象直接进入老年代
Minor GC后的对象太多,无法放入Survivor区怎么办?
老年代空间分配担保规则
老年代垃圾回收算法
昨日思考题解答
今日思考题

接着假如新生代的Eden区和Survivor1区都快满了,此时就会触发Minor GC,把存活对象转移到Survivor2区去

然后接着就会使用Eden区和Survivor2区,来分配新的对象,如下图所示。

这个过程上篇文章已经讲的非常的清楚了。那么这篇文章我们就来依次看看各种情况下,对象是如何进入老年代的,以及老年代的垃圾回收算法是什么样的?

所以你无论新生代怎么垃圾回收,类似这种对象都不会被回收掉的。



这个时候就必须得把这些对象直接转移到老年代去,如下图所示。

为啥检查这个呢?因为最极端的情况下,可能新生代Minor GC过后,所有对象都存活下来了,那岂不是新生代所有对象全部要进入老年代?如下图。

,发现老年代的可用内存已经小于了新生代的全部对象大小了,就会看一个“-XX:-HandlePromotionFailure”的参数是否设置了
如果有这个参数,那么就会继续尝试进行下一步判断。
下一步判断,就是看看老年代的内存大小,是否大于之前每一次Minor GC后进入老年代的对象的平均大小。
举个例子,之前每次Minor GC后,平均都有10MB左右的对象会进入老年代,那么此时老年代可用内存大于10MB。
这就说明,很可能这次Minor GC过后也是差不多10MB左右的对象会进入老年代,此时老年代空间是够的,看下图。

如果上面那个步骤判断失败了,或者是“-XX:-HandlePromotionFailure”参数没设置,此时就会直接触发一次“Full GC”,就是对老年代进行垃圾回收,尽量腾出来一些内存空间,然后再执行Minor GC。
如果上面两个步骤都判断成功了,那么就是说可以冒点风险尝试一下Minor GC。此时进行Minor GC有几种可能。
第一种可能,Minor GC过后,剩余的存活对象的大小,是小于Survivor区的大小的,那么此时存活对象进入Survivor区域即
第二种可能,Minor GC过后,剩余的存活对象的大小,是大于 Survivor区域的大小,但是是小于老年代可用内存大小的,此时就直接进入老年代即可。
第三种可能,很不幸,Minor GC过后,剩余的存活对象的大小,大于了Survivor区域的大小,也大于了老年代可用内存的大小。此时老年代都放不下这些存活对象了,就会发生“Handle Promotion Failure”的情况,这个时候就会触发一次“Full GC”。
Full GC就是对老年代进行垃圾回收,同时也一般会对新生代进行垃圾回收。
因为这个时候必须得把老年代里的没人引用的对象给回收掉,然后才可能让Minor GC过后剩余的存活对象进入老年代里面。
如果要是Full GC过后,老年代还是没有足够的空间存放Minor GC过后的剩余存活对象,那么此时就会导致所谓的“OOM”内存溢出了
因为内存实在是不够了,你还是要不停的往里面放对象,当然就崩溃了。
这段规则有点烧脑,但是我觉得如果大家仔细对这段文字多看两遍,然后结合我们的图,脑子里想一想,基本都能看懂这个规则。
7、老年代垃圾回收算法
其实把上面的内容都看懂之后,大家现在基本就知道了Minor GC的触发时机,然后就是Minor GC之前要对老年代空间大小做的检查
包括检查失败的时候要提前触发Full GC给老年代腾一些空间出来,或者是Minor GC过后剩余对象太多放入老年代内存都不够,也要触发Full GC。包括这套规则,还有触发老年代垃圾回收的Full GC时机,都给大家讲清楚了。
简单来说,一句话总结,对老年代触发垃圾回收的时机,一般就是两个:
要不然是在Minor GC之前,一通检查发现很可能Minor GC之后要进入老年代的对象太多了,老年代放不下,此时需要提前触发Full GC然后再带着进行Minor GC;
要不然是在Minor GC之后,发现剩余对象太多放入老年代都放不下了。
那么对老年代进行垃圾回收采用的是什么算法呢?
简单来说,老年代采取的是标记整理算法,这个过程说起来比较简单
大家看下图,首先标记出来老年代当前存活的对象,这些对象可能是东一个西一个的。

接着会让这些存活对象在内存里进行移动,把存活对象尽量都挪动到一边去,让存活对象紧凑的靠在一起,避免垃圾回收过后出现过多的内存碎片
然后再一次性把垃圾对象都回收掉,大家看下图。

大家一定要注意一点,这个老年代的垃圾回收算法的速度至少比新生代的垃圾回收算法的速度慢10倍。
如果系统频繁出现老年代的Full GC垃圾回收,会导致系统性能被严重影响,出现频繁卡顿的情况。
所以后面用各种案例给大家展现出来的,就是在各种业务系统的生产故障下,怎么去一步一步分析到底为什么频繁的Full GC,然后怎么来调整JVM的各种参数进行优化。
其实大家如果透彻理解了最近的几篇文章涵盖的JVM的运行原理,就会知道,所谓JVM优化,就是尽可能让对象都在新生代里分配和回收,尽量别让太多对象频繁进入老年代,避免频繁对老年代进行垃圾回收,同时给系统充足的内存大小,避免新生代频繁的进行垃圾回收。
关于如何优化JVM,后续会有大量的案例带着大家去实战,而且会给出模拟生产的代码,让大家运行起来看到模拟出来的案发现场是如何导致JVM频繁GC的,对性能是如何影响的,然后再一步一步来优化JVM参数解决性能问题。
8、昨日思考题
可以借助那个方法估算一下,每秒钟系统会使用多少内存空间,然后多长时间会触发一次垃圾回收,垃圾回收之后,你们系统内大体会有多少对象存活下来?为什么?都有哪些对象会存活下来?存活下来的对象会占多少内存空间?
触发Minor GC之前会如何检查老年代大小,涉及哪几个步骤和条件?
什么时候在Minor GC之前就会提前触发一次Full GC?
Full GC的算法是什么?
Minor GC过后可能对应哪几种情况?
哪些情况下Minor GC后的对象会进入老年代?
End
版权:公众号儒猿技术窝
未经许可不得传播,如有侵权将追究法律责任