标签:关系 forward href roots michael 暂停 存在 右上角 image
目录
Paul R.Wilson、Michael S.Lam、Thomas G.Moher,1991
这个方法只是近似深度优先搜索,但可以做到深度优先执行GC复制算法。
假设所有对象都是2个字,下图所示是对象间的引用关系。
下图所示是执行该算法时候,各个对象所在的页面(页面,在操作系统,和计算机组成原理课程中都有)。
右上角数字是页面编号,假如说页面容量是6个字(只能放3个对象)。
从上图不难看出,A,B,C是相邻的,这就是比较理想的状态。对于其他对象来说,降低了连续读取的可能性,降低了缓存命中率。
在下面1-4页中,同一个页面的对象甚至都没有引用关系(页面1中D和页面2中HI,有引用关系,但是不命中,需要读内存数据到catch),这样就不得不从内存上再去读。一直这样下去可想而知,有很多的对象会是这样的分布状态。
在这个方法中有下面四个变量。
先复制A到To空间,然后复制他们的孩子B,C,都被放置到了0页。如下图示:
这样就搜索完了第0页($major_scan),虽然还没有搜索完子对象,但是孩子没有孩子,所以现在这个状态,和搜索完后是一样的。
该方法是如何安排对象的呢?如下图示:
很明显能看出与Cheney的复制算法不同,不管下一个页面在哪里,对象之间都存在引用关系。
该方法,采用了不完整的广度优先,它实际上是用到了暂停的。从一开始我们就根据关系,然后进行暂停,将有关系的对象安排到了一个页面中。
GC复制算法最大的缺点就是只能利用半个堆。
但是如果我们把空间分成十份,To空间只占一份那么这个负担就站到了整体的1/10。剩下的8份是空的,在这里执行GC标记清除算法。
多空间复制算法,实际上就是把空间分成N份,对其中两份进行GC复制算法,对其中(N-2)份进行GC标记-清除。
muti_space_copying(){
$free = $heap[$to_space_index]
for(r :$roots)
*r = mark_or_copy(*r)
for(index :0..(N-1))
if(is_copying_index(index) == FALSE)
sweep_block(index)
$to_space_index = $from_space_index
$from_space_index = ($from_space_index +1) % N
}
将堆分为N等份,分别是$heap[0],$heap[1]...$heap[N-1]。这里的$heap[$to_space_index]表示To空间,每次执行GC时,To空间都会像$heap[0],$heap[1]...$heap[N-1],$heap[0],这样进行替换。Form空间在To空间的右边,也就是$heap[1]...$heap[N-1]。
mark_or_copy(obj){
if(is_pointer_to_from_space(obj) == True)
return copy(obj)
else
if(obj.mark == FALSE)
obj.mark == TRUE
for(child :children(obj))
*child = mark_or_copy(*child)
return obj
}
调查参数obj是否在From空间里。如果在From空间里,那么它就是GC复制算法的对象。这时就通过copy()函数复制obj,返回新空间的地址。
如果obj不在From空间里,它就是GC标记-清除算法的对象。这时要设置标志位,对其子对象递归调用mark_or_copy()函数。最后不要忘了返回obj。
copy(obj){
if(obj.tag != COPIED)
copy_data($free, obj, obj.size)
obj.tag = COPIED
obj.forwarding = $free
$free += obj.size
for(child :children(obj.forwarding))
*child = mark_or_copy(*child)
return obj.forwarding
}
递归调用不是copy()函数,而是调用mark_ or_copy()函数。如果对象*child是复制对象,则通过mark_or_copy() 函数再次调用这个copy()函数。
将内存分为4等份。如下图示:
To空间$heap[0]空着,其他三个都被占用。这个状态下,GC就会变为如下如示:
我们将$heap[0]作为To空间,将$heap[1]作为From空间执行GC复制算法。此外$heap[2]和$heap[3]中执行GC标记-清除算法,将分块连接到空闲链表。
当mutator申请分块时候,程序会从空闲链表或者$heap[0]中分割出块给mutator。
接下来,To空间和From空间都向后移动一个位置。mutator重新开始。
这次$heap[1]是To空间,$heap[2]From空。这种状态下执行就会变为下图所示:
$heap[2]的活动对象都被复制到了$heap[1]中,在$heap[0]和$heap[3]中执行GC标记清除。然后From和To后移一次。
优点
提高内存利用率:没有将内存空间二等分,而是分割了更多空间。
缺点
GC标记清除,分配耗时,分块碎片化。当GC标记清除算法的空间越小的时候,该问题表现的越不突出。例如将内存分为3份的情况下。
Copying GC (Part two :Multi Space Copying GC)
标签:关系 forward href roots michael 暂停 存在 右上角 image
原文地址:https://www.cnblogs.com/Leon-The-Professional/p/9992345.html