被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解( 三 )


被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解

文章插图
?程序运行一度时间后的状态
5.4 执行第2次MinorGC后状态新对象分配Eden区空间不足,又触发了第二次MinorGC,第二次MinorGC与第一次GC时在Eden区的操作是一样的:将Eden区存活的对象复制到S1区,然后在清空整个Eden区,同时也将S0区存活的对象复制到S1区并将对象的年龄加1,再清空S0区,GC后的状态如下图所示:
被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解

文章插图
?执行第二次MinorGC后状态
5.5 第2MinorGC程序运行一段时间后状态经过第二MinorGC后程序又运行了一段时间,Eden区中有生成了很多对象,S1区也有一个对象可回收 。
被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解

文章插图
第二MinorGC程序运行一段时间后状态
5.6 第15MinorGC后内存状态在接下来的每次MinorGC时,都是第二次一样,从Eden区和survivor非空白区移动存活对象到survivor区中空白区域,并清空这两个区域内存空间,存活对象每此从survivor两个区域移动一次,对象年龄加1,下图表示经过了15次MinorGC后的堆内存状态 。
被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解

文章插图
?经过15次MinorGC后的内存状态
对于年轻代区域的内存收集,使用的是标记-复制算法,只是为了减少复制算法空白区域的内存浪费,并不是将内存一份为二,而是巧妙的将内存分为三个区域,预留的空白区域只占整个年轻代区域的1/10 。
5.7 对象如何进入老年代以上是年轻代的分配与回收问题,那对象如何进入老年代呢?个人认为对象进入老年代,可以分为2种类型6种情况 。
被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解

文章插图
?对象晋升入老年代
第一种类型--直接分配:对象创建时直接分配到老年代具体分为3种情况 。
  • 超过虚拟机PretenureSizeThreshold参数设置大小的对象,该参数的默认值是0,也就是说任何大小的对象都会先分配到Eden区 。
  • 超过Eden大小的对象
  • 如果新生代分配失败,一个大数组或者大字符串
第二种类型--从年轻代晋升:从年轻代空间晋升到老年代也可分为3种情况 。
  • 新生代分配担保,在执行MinorGC时要将Eden区存活的对象复制到Survivor区,但是Survivor区默认空间是只有新生代的2/10,实际使用的只有1/10,当Survivor区内存不够所有存活对象分配时,就需要将Survivor无法容纳的对象分配到老年代去,这种机制就叫分配担保 。
  • 对象年龄超过虚拟机MaxTenuringThreshold的设置值,最大为15,
  • Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半(TargetSurvivorRatio),年龄大于或等于该年龄的对象直接进入老年代 。
内存分配担保机制
在执行MinorGC时要将Eden区存活的对象复制到Survivor区,但是Survivor区默认空间是只有新生代的2/10,实际使用的只有1/10,当Survivor区内存不够所有存活对象分配时,就需要Survivor无法容纳将对象分配到老年代空间中,这种机制就叫分配担保,但是,老年代的空间也是有限的,如果老年代中空间也不够的话,那只能乖乖的执行一次FullGC了 。
5.8 老年代回收算法-FullGC当有对象要进入老年代,而老年代空间又不足时就会触发FullGC,当然,反过来说触发FullGC的条件不仅仅只是老年代空间不足,FullGC使用的算法是上面说的标记-整理算法 。
被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解

文章插图
?完整堆内存回收过程
六、总结判断对象是否可以回收是垃圾回收的基础与前提,通过可达性分析从GCRoots开始进行"顺藤摸瓜"找到不可达对象(可回收) 。
对象生命周期的特征"朝生夕灭"与"越战越强"是垃圾回收算法的理论基础 。
基础的垃圾回收算法有3种分别是 标记-清除算法、标记-负责算法、标记整理算法,都有各自的适应场合与优缺点 。
分代垃圾算法根据对象生命周期的特征,将其划分到不同的区域,从而使用最适合的垃圾算法来进行优化 。
在JDK8默认的配置下使用 新生代,老年代的垃圾回收策略,新生代区域使用标记-复制算法,老年代区域使用标记-整理算法 。
作者:攀岩飞鱼
原文链接:https://xie.infoq.cn/article/9d4830f6c0c1e2df0753f9858


推荐阅读