4 GC复制算法算法
Copying GC是Marvin L.Minsky在1963年研究出来的算法。就是指把某个空间里的活动对象复制到其它空间,把原空间里的全部对象都回收掉。在此,将复制活动对象的原空间称为From空间,将粘贴活动对象的新空间称为To空间。缓存
4.1 什么是GC复制算法
GC复制算法是利用From空间进行分配的。当From空间被彻底占满时,GC会将活动对象所有复制到To空间。当复制完成后,该算法会把From空间和To空间互换,GC也就结束了。From空间和To空间大小必须一致。这是为了保证能把From空间中的全部活动对象都收纳到spa
4.1.1 执行过程
假设目前堆里的配置以下。
指针
执行GC。首先是从根直接引用的对象B和G,B先被复制到了To空间。对象
将B被复制后生成的对象称为B’。在From空间中B已经被打上了复制完成标签。可是,这里只把B’复制了过来,它的子对象A还在From空间里,下面把A复制到To空间里。
ip
此次才是真正意义上复制了B。由于A没有子对象,因此对A的复制就完成了。 内存
接下来,要和复制B同样从根引用复制G,以及其子对象E。虽然B也是G的子对象,不过由于已经复制完B了,因此只要把从G执行B的指针转换到B’上。 it
最后,只要把From空间和To空间互换,GC就结束了。 class
对象C、D、F由于无法从根查找,因此会被回收。这里程序是以B、A、G、E的顺序搜索对象的,使用的是深度优先搜索。cli
4.2 优势
4.2.1 优秀的吞吐量
GC标记-清除算法消耗的吞吐量是搜索活动对象(标记阶段)所花费的时间和搜索总体堆(清除阶段)所花费的时间之和。
另外一方面,由于GC复制算法只搜索并复制活动对象,因此跟通常的GC标记-清除算法相比,它能在短期内完成GC,也就是说其吞吐量优秀。
尤为是堆越大,差距越明显。GC标记-清除算法在清除阶段所花费的时间会不断增长,但GC复制算法就不会。由于它消耗的时间是与活动对象的数量成比例的。
4.2.2 可实现高速分配
GC复制算法不使用空闲链表,由于分块是一块连续的内存空间。所以,调查这个分块的大小,只要这个分块大小不小于所申请的大小,那么移动指针就能够进行分配了。
比起GC标记-清除算法和引用计数算法等使用空闲链表的分配,GC复制算法明显快得多。使用空闲链表是为了找到知足要求的分块,须要遍历空闲链表,最坏的状况是咱们不得不从空闲链表中取出最后一个分块,这样就用了大量时间把全部分块都调查一遍。
4.2.3 不会发生碎片化
基于算法性质,活动对象被集中安排在From空间的开头。像这样把对象从新集中,放在堆中一端的行为叫做压缩。在GC复制算法中,每次运行GC时都会执行压缩。
所以GC算法有个很是优秀的特色,就是不会发生碎片化,也就是说能够安排分块容许范围内大小的对象。
另外一方面,在GC标记-清除算法等GC算法中,一旦安排了对象,原则上就不能再移动它了,因此会多多少少产生碎片化。
4.2.4 与缓存兼容
在GC复制算法中有引用关系的对象会被安排在堆里离彼此较近的位置。B’引用A’,G’引用E’的顺序排列。这种状况有一个优势,那就是mutator执行速度极快。不少CPU都经过缓存来来高速读取位置较近的对象。这也是借助压缩来完成的,经过压缩来把有引用关系的对象安排在堆中较近的位置。
4.3 缺点
4.3.1 堆使用率低下
GC复制算法把堆分红二等分,一般只能利用其中一半来安排对象。也就是说只有一半堆能被使用,相比其余能使用整个堆的GC算法而言,这是GC复制算法的一个重大缺陷。
4.3.2 不兼容保守式GC算法
GC标记-清除算法有着跟保守式GC算法相兼容的优势。由于GC标记-清除算法不用移动对象。
另外一方面,GC复制算法必须移动对象重写指针,因此有着跟保守式GC算法不相容的性质。虽然有限制条件,GC复制算法和保守式GC算法能够进行组合。