新生代有哪几种情况进入老年代
1.达到指定年龄(可设置阈值)通常为15次,直接进入老年代
2.动态年龄判断:如果相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代
3.大对象(可设置阈值)直接进入老年代
4.eden区minor(yong)GC后剩下的比survivor区大,直接进入老年代
老年代空间分配担保规则
问题:如果新生代里有大量对象存活下来,确实是自己的Survivor区放不下了,必须转移到老年代去,那么如果老年代里空间也不够放这些对象呢?这怎么办呢?
1.首先,在执行任何一次Minor GC之前,JVM会先检查一下老年代可用的可用内存空间,是否大于新生代所有对象的总大小。
(1)如果说发现老年代的内存大小是大于新生代所有对象的,此时就可以放心大胆的对新生代发起一次Minor GC了,因为即使Minor GC之后所有对象都存活,Survivor区放不下了,也可以转移到老年代去。
(2)假如Minor GC之前,发现老年代的可用内存已经小于了新生代的全部对象大小了,就会看一个“-XX:-HandlePromotionFailure”的参数是否设置了。
如果有这个参数,那么就会继续尝试进行下一步判断。
下一步判断,就是看看老年代的剩余内存大小,是否大于之前每一次Minor GC后进入老年代的对象的平均大小。
如果判断老年代剩余内存小于均值了,或者是“-XX:-HandlePromotionFailure”参数没设置,此时就会直接触发一次“FullGC”,就是对老年代进行垃圾回收,尽量腾出来一些内存空间,然后再执行Minor GC。
如果上面两个步骤都判断成功了,那么就是说可以冒点风险尝试一下Minor GC。此时进行Minor GC有几种可能。
第一种可能,Minor GC过后,剩余的存活对象的大小,是小于Survivor区的大小的,那么此时存活对象进入Survivor区域即可。
第二种可能,Minor GC过后,剩余的存活对象的大小,是大于 Survivor区域的大小,但是是小于老年代可用内存大小
的,此时就直接进入老年代即可。
第三种可能,很不幸,Minor GC过后,剩余的存活对象的大小,大于了Survivor区域的大小,也大于了老年代可用内存的大小。此时老年代都放不下这些存活对象了,就会发生“Handle Promotion Failure”的情况,这个时候就会触发一次“Full GC”。
Full GC就是对老年代进行垃圾回收,同时也一般会对新生代进行垃圾回收。
如果要是Full GC过后,老年代还是没有足够的空间存放Minor GC过后的剩余存活对象,那么此时就会导致所谓的“OOM”内存溢出了
老年代垃圾回收算法
一句话总结,对老年代触发垃圾回收的时机,一般就是两个:
1.在Minor GC之前,一通检查发现很可能Minor GC之后要进入老年代的对象太多了,老年代放不下,此时需要提前触发Full GC然后再带着进行Minor GC;
2.Minor GC之后,发现剩余对象太多放入老年代都放不下了。
此时触发老年代垃圾回收,老年代采取的是标记整理算法
下图,首先标记出来老年代当前存活的对象,这些对象可能是东一个西一个的。
接着会让这些存活对象在内存里进行移动,把存活对象尽量都挪动到一边去,让存活对象紧凑
的靠在一起,避免垃圾回收过后出现过多的内存碎片,然后再一次性把垃圾对象都回收掉,如下图。
这个老年代的垃圾回收算法的速度至少比新生代的垃圾回收算法的速度慢10倍,实际上就是因为新生代采用的是优化后的复制算法,老年代使用的标记-清理-整理算法。
如果系统频繁出现老年代的Full GC垃圾回收,会导致系统性能被严重影响,出现频繁卡顿的情况。