【003】垃圾回收算法-BiBOP、位图标记 、延迟清除法

1.BiBOP

 BiBOP是Big Bag Of Pages 的缩写。这么说可能比较难懂,用一句话概况就是”将大小相近的对象整理成固定大小的块 进行管理的做法“。

上一篇介绍过,GC标记-清除算法中会发生碎片化。碎片化的原因之一就是堆上杂乱散布着大小各异的对象。

对此,我们可以用这个方法:把堆分割成固定大小的块,让每个块只能配置同样大小的对象。这就是BiBOP法。

 

上图,3个字的对象被整合分配到左数第一个和第三个块,2个字的对象被整合分配到左数第二个块。像这样配置的对象,就会提高内存的使用效率。因为每个块中只能配置同样大小的对象, 所以不可能出现大小不均匀的分块。

但是,使用BiBOP法并不能完全消除碎片化。比方说在全部用于2个字的块中,只有1到2个活动对象;这种情况下就不能算是有效利用了堆。

BiBOP法原本是为了消除碎片化,提高堆使用效率而采用的方法。但像上面这样,在多个块中分散残留着同样大小的对象,反而会降低堆的使用效率。

意思是为了很少量的对象,也得维护一份相等大小的块,这样就会导致浪费了部分内存。

2.位图标记

在单纯的标记-清除算法中,用于标记的位是被分配到各个对象的头中的。也就是说,算法是把对象和头一并处理的。然而上一篇介绍的时候,这个跟写时复制技术不兼容。

对此我们有个方法,那就是只收集各个对象的标志位并表格化,不跟对象一起管理。在标记的时候,不在对象的头里置位,而是在这个表格中的特定场所置位。像这样集合了用于标记的位的表格称为”位图表格“(bitmap table ),利用整个表格进行标记的行为称为”位图标记“。位图表格的实现方法有多种,例如散列表和树形结构等。

和在对象的头中直接标志位的方法相比,该方法稍微有些复杂,但这样有两个好处。

优点

与写时复制结束兼容

以往的标记操作都是直接对对象设置标志位,这会产生无谓的复制。

然而,使用位图标记是不会对对象设置标志位的,所以也不会发生无谓的复制。当然,因为对位图表格进行了重写,所以在此处会发生复制。不过,因为位图表格非常小,所以即使被复制也不会有什么大的影响。

此外,以上问题只发生在写时复制技术的运行环境(Linux等)中,以及频繁执行fork()函数的应用程序中。也就是说,它对于一般的程序来说完全不是问题。

2.清除操作更高效

不仅在标记阶段,在清除阶段也可以得到好处。以往的清除操作都必须遍历整个堆,把非活动对象链接到空闲链表,同时取消活动对象的标志位。

利用了位图表格的清除操作则把所有对象的标志位集合到一处,所以可以快速消去标志位。

3.注意事项

在进行位图标记的过程中,有件事情我们必须注意,那就是对象地址和位图表格的对应。就像之前和大家说明的那样,想通过对象的地址与其对应的标志位的位置,是要进行位运算的。然而在堆有多个的情况下,一般会为每个堆都准备一个位图表格。

3.延迟清除法

我们上一篇,提到过,清除操作所花费的时间是与堆大小成正比的。也就是说,处理的堆越大,GC标记-清除法所花费的实际就越长,结果就会妨碍到mutator的处理。

延迟清除法(Lazy Sweep)是缩减因清除操作而导致的mutator最大暂停时间的方法。在标记操作结束后,不一并进行清除操作,而是如其字面意思一样让它”延迟“。通过”延迟“来防止mutator长时间暂停。那么,延迟清除操作意味着什么呢?

延迟清除的核心 本人理解的意思是:用到了,才开始触发标记清除操作。

有延迟清除法就够了吗?

我们已经知道,通过延迟清除法可以缩减mutator的暂停时间,不过这是真的码?稍微想想看就会明白,延迟清除的效果是不均衡的。打个比方,假设刚刚标记完的堆的情况如下图:

 也就是说,垃圾变成了垃圾堆,活动对象变成了活动对象堆,它们形成了一种邻接的状态。在这种情况下,程序在清除垃圾较多的部分时能马上获得分块,所以能减少mutator的暂停时间。然而一旦程序开始清除活动对象周围,就怎么也无法获得分块了,这样就增加了mutator的暂停时间。

结果,如果一下子清除的堆大小不一定,那么mutator的暂停时间就会增大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值