GC 收集器算法总结

来源:互联网 发布:虚拟机安装ubuntu出错 编辑:程序博客网 时间:2024/06/04 19:50

(原文链接:GC 收集器算法总结)

GC 的几种收集器应用于不同场合,他们有着不同的实现及流程,本节就将几种收集器用到的算法总结一下,更利于大家理解。默认的本节依然以HotSpot JVM 实现为基础。


        1.Mark-Sweep(标记-清理算法)
        标记-清扫/清理算法是最基础的收集算法,此算法有两个阶段:"标记"和"清理"。

        标记阶段:首先标记出所有需要回收的对象;
        清理阶段:清理之前标记过的所有垃圾对象;



 

        之所以说它是最基础的收集算法,是因为他有比较严重的缺点:
        (1)效率问题,标记和清理过程的效率都不高;
        (2)空间问题,标记清理之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

 

        2.Copying(复制算法)
        复制算法简单来讲就是将可用内存划分为两块区域(通常为相等大小),每次只使用其中的一块。当有新的活动对象加入空闲内存时,同时将源内存(From)还存活的对象一同复制到空闲内存中去,然后再将此块内存进行清理。这样使得GC 每次只要对源内存区域进行垃圾回收即可,不必再去考虑内存分配时遗留的碎片等复杂问题。分配新内存时,只需向后移动堆顶指针,按顺序分配内存即可。Copying 算法实现简单,运行高效。但是缺点也比较明显,就是需要额外的内存空间。
        正因为Copying 算法的执行效率非常高,所以在HotSpot JVM 中被用来管理新生代内存空间,HotSpot JVM 中将Heap 内存划分为新生代与老年代(注意:方法区可称为永久代,但不等于永久代)。又将新生代划分为Eden(伊甸园) 与2块Survivor Space(幸存者区) ,然在Eden -->Survivor Space 与From Survivor Space 与To Survivor Space 之间实行Copying 算法。

        HotSpot JVM 中的复制算法:



 

        商业虚拟机都采用这种收集算法来回收新生代,IBM的专门研究表明,新生代中的对象98%是朝生夕死的,所以并不需要按照1∶1的比例来划分内存空间,而是将内存分为一块较大的Eden 空间和两块较小的Survivor 空间,每次使用Eden 和其中的一块Survivor。当回收时,将Eden 和Survivor 中还存活着的对象一次性地拷贝到另外一块Survivor 空间上,最后清理掉Eden 和刚才用过的Survivor 的空间。HotSpot虚拟机默认Eden 和Survivor 的大小比例是8∶1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的内存是会被“浪费”的。当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor 空间不够用时,需要依赖其他内存(例如老年代)进行分配担保(Handle Promotion)。

        内存的分配担保就好比我们去银行借款,如果我们信誉很好,在98%的情况下都能按时偿还,于是银行可能会默认我们下一次也能按时按量地偿还贷款,只需要有一个担保人能保证如果我不能还款时,可以从他的账户扣钱,那银行就认为没有风险了。内存的分配担保也一样,如果另外一块Survivor 空间没有足够的空间存放上一次新生代收集下来的存活对象,这些对象将直接通过分配担保机制进入老年代。


        3.Mark-Sweep-Compact(标记-清理-压缩算法)
        复制算法在对象存活率较高时就要执行较多的复制操作,效率将会变低。更重要的是,如果不想浪费50%的内存空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。

        根据老年代的特点,提出了Mark-Sweep-Compact(标记-清理-压缩)算法,此算法在“标记-清理”算法基础上改进,在清理完成之后增加了压缩阶段,压缩阶段是将清理过后出现的内存碎片按规则进行排序整理,将碎片依次移动到heap 内存的低端压实,从而内存的高端就空出一块较大的空间。这样在新的大对象创建后就有足够的空间存储他了。

        标记-清理-压缩流程如图:



 


        4.分代收集算法

        stop-the-world 的缺点是:每一次GC收集时,所有的程序活动都将暂停直至GC 工作完毕返还控制权,然而大部分程序中的对象都具有很短的生命周期,只有少数对象会持久贮存在内存中。
        分代收集算法就是根据对象的不同生命周期分别管理,HotSpot JVM 中将对象分为我们熟悉的“新生代”,“老年代”和“永久代”分别管理。这样做的好处就是可以根据不同类型对象进行不同策略的管理,例如新生代中对象更新速度快,就会使用效率较高Copying(复制算法)。老年代中内存空间相对分配较大,而且时效性不如新生代强,就会常常使用Mark-Sweep-Compact(标记-清理-压缩)算法。



 
        5.G1算法
        G1 的原理在于将堆划分成等一系列大小的区域,每一个区域都有一个对应的remembered set 结构,用来记录指向这个区域中的地址的其他区域的指针。 在垃圾回收时,选择记录最少的一个区域进行,按找这种方式选择出来的区域,通常是有用数据最少、垃圾最多的区域,这也就是“Garbage-first”名称的由来。假如没有外部的指针指向这个区域,就可以直接回收整块区域而不用进行内存Copy。


0 0
原创粉丝点击