垃圾回收復(fù)制算法的基本思想很直觀,甚至看上去浪費(fèi)。將現(xiàn)有堆一分為二,一個(gè)用完后,將活動(dòng)對(duì)象拷貝到另一半。但是這樣做卻有一些比較明顯的優(yōu)點(diǎn)。
先來看下具體算法。
看上去簡(jiǎn)單,其實(shí)還是有一些要注意的地方。
第一是防止重復(fù)拷貝,對(duì)象之間的引用可以很復(fù)雜,各種交叉;第二是拷貝后,新老堆中的引用關(guān)系要縷順。
copying() { $free = $to_start for (r : $root) *r = copy(r) // 注意,這里實(shí)際是一個(gè)update,將對(duì)象替換 swap($from_start, $to_start) }
上述free是新堆的起點(diǎn)指針,復(fù)制回收剛開始時(shí),free指向起點(diǎn)。開頭描述的兩個(gè)要注意的地方可以通過在老堆中的對(duì)象中引入兩個(gè)字段來解決,分別是tag、forwarding,因?yàn)槔隙阎袃?nèi)存已經(jīng)無用,兩字段可以在對(duì)象原先的字段中重用。具體見下算法:
// 這里,傳給copy的對(duì)象,一定是舊堆的copy(obj) { if obj.tag != COPIED // 重要,在老堆的對(duì)象中,標(biāo)志這對(duì)象已經(jīng)拷走。 copy_data($free, obj, obj.size) // 拷貝到free obj.tag = COPIED obj.forwarding = $free // 重要!obj是老堆中對(duì)象,forwarding字段指向了新堆中的同一對(duì)象??! $free += obj.size for (child :