深入理解java虚拟机--->垃圾回收算法

    xiaoxiao2021-03-25  149

    一、标记-清除算法

      分为两个步骤,标记与清除,首先根据GC Roots算法,标记需要被回收的对象,然后在标记完成后,回收掉所有标记的对象。      标记-清除算法是很基础的算法,有两个缺陷。      一、标记与清除的效率不高。   二、标记-清除算法结束回收后,内存中很可能留下很多不连续的内存空间,当一个占用内存比较大对象进入时,有可能内存中没有满足这个对象的连续的区域,从而导致提前进行一次垃圾回收。

    二、复制算法

      初期的复制算法是这样的,将内存划分为两片一样大的区域,每次只使用其中一半,当其中一块内存使用完毕,将其中仍然还存活的对象复制到另一片区域,然后对刚才使用过的区域进行清理,这样就解决了内存中的内存碎片的问题。      然而这样的算法是弊端的,每次都只能使用一半的内存,而且,当出现极端情况,存活的对象很多的时候,复制对象到另一半区域的成本过大。      下面是复制算法的改良算法,经过研究,大多数对象的生命周期都十分短暂,他们是”朝生夕灭”的,将新生代划分为两类区域,Eden区和survivor区,默认比例为8 : 1,其中,Eden区一块,survivor区两块。      每次执行时,只使用一块Eden区和一块Survivor区,也就是说,每次都只有10%的空间被浪费。      当进行回收时,将Eden区与Survivor区中还存活的对象,复制到另一块还存活的Survivor空间。如果,原Eden区与Survivor中的还存活的对象的所占的内存,大于另一个空余的Survivor区域的话,会进行分配担保。在将Survivor填满后,剩余的对象将被放入老年代。         那么什么是分配担保呢?   

    在发生Minor GC之前,虚拟机会检查老年代之中的最大可用连续空间是否大于新生代所有对象的总空间。如果这个条件成立,那么Minor GC就是安全的,如果不成立则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管这次Minor GC是有风险的,如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。

    上文引用自《深入理解java虚拟机》

      这可能很难理解,我们知道,在复制算法之中,我们将年轻代划分为Eden区与Survivor区,Survivor区又分为from space与 to space。我们可以将Eden区以及from space比喻为伊甸园,人们生活的地方,将GC比喻为灾难,在灾难来临前,人们计划将妇女,孩子和年轻男子送走,送往to space,如果,to space中的区域无法承载那么多的人,这些人就会被送往老年代,在送往老年代之前,需要调查老年代之中是否有这样一块连续的地方供多出来的这一部分人们生存,如果有,那么就接收过来,并触发Minor GC,如果没有这样一块空间存在,这些人需要得到HandlePromotionFailure这个门卫的允许,如果他允许,会查看,历次以往发生灾难时从年轻代逃离到老年代的人们的平均值,如果小于当前老年代最大连续空间的值,就接收这些人并且触发Minor GC,如果大于,或者HandlePromotionFailure门卫不允许,就触发Full GC。

    三、标记-整理

      起初我理解标记整理算法,认为它是先做一次标记清除,然后将剩余的对象集中存放在一起,这样的想法是错误的。   标记-整理算法是将所有的存活的对象向一端移动,然后直接清理掉边界外的内存。此算法都用于老年代。

    转载请注明原文地址: https://ju.6miu.com/read-3548.html

    最新回复(0)