标签:href under 改变 产生 付出 意思 必须 技术分享 new
目录
Robert A.Saunders 对堆执行两次搜索
Two-Finger 算法,必须将所有对象整理成大小一致。它没有在对象的头中设立forwarding指针,而是在对象的域中设立forwarding指针即可。
Two-Finger算法由一下两个步骤构造。
在Lisp2算法中,是将对象移动到堆的一端。在Two-Finger中,操作对象向左滑动,通过执行压缩算法来填补空闲空间。此时为了让更好的填补空间,所以对象大小必须一样。
移动前的对象都会被保留(图的白色对象)。因为在Two-Finger算法中,我们要利用放置非活动对象的空间来作为活动对象的目标空间,这是为了让移动前的对象不会在GC过程中被覆盖掉。这样一来,我们就能把forwarding指针设定在这个移动前 的对象的域中,没有必要多准备出 1 个字了。
move_obj(){
$free = $heap_start
live = $heap_end - OBJ_SIZE
while(TRUE)
while($free.mark == TRUE) //从前往后寻找非活动对象
$free += OBJ_SIZE
while(live.mark == FLASE) // 重后往前 寻找活动对象
live -= OBJ_SIZE
if($free < live) // 判断交换条件
copy_data($free, live, OBJ_SIZE)
live.forwarding = $free
live.mark = FALSE
else
break
}
接下来寻找指向移动前的对象的指针,把它更新,使其指向移动后的对象。更新指针操作的是adjust_ptr()函数。
adjust_ptr(){
for(r :$roots)
if(*r >= $free)
*r = (*r).forwarding
scan = $heap_start
while(scan < $free)
scan.mark = FALSE
for(child :children(scan))
if(*child >= $free)
*child = (*child).forwarding
scab += OBJ_SIZE
}
优点:Two-Finger 算法能把 forwarding 指针设置在移动前的对象的域里,所以不需要额外的内存 空间以用于 forwarding 指针。只需要2次搜索堆。
缺点: Two-Finger 算法则不考虑对象间的引用关系,一律对其进行压缩,结果就导致对象的顺序在压缩前后产生了巨大的变化。因此,我们无法更好的使缓存。 对象大小必须一样。
B.K.Haddon 和 W.M.Waite, 1967
这个算法使用表格来进行压缩,和Two-Finger一样都是执行两次压缩。
表格算法通过以下2个步骤来执行压缩。
步骤1是让连续的活动对象群一并移动。(和前面所接触到的压缩算法都不同)。除此之外还要预留更新指针所用到的信息,这里我们使用间隙表格。
间隙表格,大概意思是“按照一个个活动对象群记录下压缩所需要的信息的表格”。这个表格事先放入移动前的对象群信息(位于对象群的首地址和较低地址的分块的总大小)。为了方便地址计算,我们将1个字的大小定为50.如下图示:
活动对象群移动前和移动后(move_obj())的状态如图示:
move_obj(){
scan = $free = $heap_start
size = 0
while(scan < $heap_end) // while 循环 1
while(scan.mark == FALSE)
size += scan.size
scan += scan.size
live = scan
while(scan.mark == TRUE) // while 循环 2
scan += scan.size
slide_objs_and_mark_bt(scan ,$free, live, size)
$free += (scan-live)
}
这时,堆的状态如下图示:
在第二个while循环中
在上一个图中,每次移动对象群的时候都需要吧信息注册到间隙表格中。注册入口是对象群的首地址live和对象群滑动大小size的组合。如下图示:
构筑间隙表格是在slide_objs_and_mark_bt()方法中指向的,下面使用图例来说明过程:
在dajust_ptr()函数中,将引用移动前的对象的指针全部换成引用移动后的对象的指针。这项操作本身和前面的两个算法中的操作是相同的。
adjust_ptr(){
for(r :$roots)
*r = new_address(*r)
scan = $heap_start
while(scan < $free)
scan.mark = FALSE
for(child : children(scan))
*child = new_address(*child)
scan += scan.size
}
下面是new_address(obj)函数
new_address(obj){
best_entry = new_bt_entry(0, 0)
for(entry :break_table)
if(entry.address <= obj && $best_entry.address < entry.address)
best_entry = entry
return obj - best_entry.size
}
上图中如果我们想知道B移动到了B?,首先就要以B的地址100为线索调查间隙表格,然后就会发现入口(100,100)是best_entry,接下来可由B的地址 100 求得 best_entry.size,即将 B 的地址减去 100 得到 B? 的地址 0。 同理,我们可以从 F 的地址 550 减去入口(550,300)中的 300,得到 F? 的地址 250。
优点:算法很好地利用了分块,保留了更换指针所必要的信息。(没有为压缩备出多余空间,)并且它没有改变对象的顺序,所以可以通过缓存来提高对象的访问速度。
缺点:维持间隙表格需要付出很高的代价,每次移动对象群都要对表格进行操作。
Mark Compact GC (Part two :Two-Finger)
标签:href under 改变 产生 付出 意思 必须 技术分享 new
原文地址:https://www.cnblogs.com/Leon-The-Professional/p/9994395.html