オブジェクトのコピー

曖昧なポインタの存在下での
Copying Garbage Collection
2001/11/13
米澤研究室修士1年
小林 義徳
発表の内容


私の研究について。なにを目指しているか。
古典的な Copying Garbage Collection
–

Cheney’s Breadth-First Copying Algorithm
Bartlett’s Mostly-Copying Collection
私の研究について。何をめざしているか。
Allocation が高速で、
言語処理系の一部として
容易に利用可能なGC
背景


言語処理系を作るにあたり、Garbage Collectorを
各処理系の作者が自前で実装しているのが現状
はっきりいって、似たようなものが世の中に存在する
のに、もう一度実装しなおすのは無駄な努力
ライブラリとして容易に利用可能な GC を
つくろう!
世の中に存在する、容易に利用可能な
GC

Boehm GC
–
–
–

全ての word がポインタか否か分からないような環境で、
Mark-Sweep GC を実現(Conservative GC)
ライブラリとして容易に利用可能。
C 言語のプログラムにすら使える(例 mozilla,w3m)
Allocation が遅いので、ML や Scheme のような、
Allocation を頻繁に行う言語処理系の GC として、
不向き。
実現したいこと(1)


言語処理系を作る際、容易にライブラリとして利用可能
メモリ上のデータの型が分からない環境でも利用可能。
–
–

各領域の word について、どれがポインタで、
どれがポインタ でないか、部分的に情報がある処理系を仮定。
Conservative GC
Fast Allocation 可能
–
–
連続した大きな領域の確保が必要
Copy GC
実現したいこと(2)

Native なコードで生成したオブジェクトについて、
型をGC に教えるも教えないも自由な Interface
–

型がわかるオブジェクトについてのみ Copy を実行
メモリの断片化を解消
–
その際、コピー量をできるだけ減らす。
今日、Bartlett’s の Mostly-Copying
Collector を選んだ動機

もともと、言語処理系用に作られたものである
–

Bartlett’s Scheme-to-C Compiler
一部ポインタか否かが分からない状況で、
Copy GC を実現している。
古典的 Copying Garbage Collector
~概要およびアルゴリズムとデータ構造~
Root から到達可能な
オブジェクトのコピーで
GC を実現
古典的 Copying Garbage Collector



完全に どの word もポインタか否か
完全に分かる状況を想定
生きているオブジェクトをコピーすることで GCを実現
Fast Allocation
–

空き領域の先頭を指すポインタをずらすだけで allocation
完了
ヒープ内メモリの断片化が決して起こらない。
Garbage Collection 用語

Root set
–
–
–
アプリケーション内の任意の場所で常に利用可能な領域
(普通、レジスタ、スタック、静的変数を Root set とする)
Root set からオブジェクトのポインタをたどっていき、到達
可能なオブジェクトは、将来アプリケーションに利用される
可能性がある。
逆に、到達可能でないオブジェクトは、将来利用されること
はない。
Garbage Collection 用語

Tracing Collector
–
–
Root set からポインタをたどっていき、到達不可能な
オブジェクトをゴミとして回収。
Root set から到達可能なオブジェクトの中にも
将来アプリケーションによって使われないものがあるが、
そのようなオブジェクトも生き残らせておく。
cf. Reference Counting
古典的 Copying Garbage Collector

アプリケーションから オブジェクトの allocate 要求があった
際、ヒープ内の空き領域が足りないとき、起動される。
–

Tracing Collector
–

アプリケーションは、GC が終わるまで一時停止、終わったら再開
Root set からポインタをたどっていき、到達可能なオブジェクトを生
き残らせる。
Root set からポインタをたどりながら、たどられたオブジェ
クトをコピーしていく。
–
コピーされなかったオブジェクトがゴミ
Copy GC の ヒープ構造


From_space と
To_space という、大きさ
が同じ 二つのヒープ。
通常、オブジェクトを
From_space より
allocate
From_space
To_space
Copy GC での Fast Allocation

Copy GC はAllocation が速い!
From_space
void* allocate(size_t size){
prev = free;
free = free + size;
free
if(free < limit){
return prev;
}else{ ・・・ }
}
Allocation 要求
limit
Copy GC の概略(1)
1. Object は From_space より
端から順に allocate
From_space
To_space
Copy GC の概略(2)
1. Object は From_space より
端から順に allocate
2. Allocation 要求に応えら
れるだけの空き領域がな
くなったら、GC を実行
From_space
To_space
Copy GC の概略(3)
From_space
3. 生きているオブ
ジェクトを
To_space にコピー
To_space
Copy GC の概略(4)
From_space
4. From_space と
To_space を入れ替
えておしまい。
これでめでたく、
allocation 要求に応
えられるようになる
To_space
古典的 Copying Garbage Collector
詳細
Cheney’s Breadth-First
Copying Algorithm
Copy GC の詳細

前提条件
–

Root set および ヒープ内の全てのデータについて、ど
の word がポインタで、どの word がポインタでないか
は全て知っているものとする。
GC の前後で、ヒープ内のオブジェクトの
グラフ構造が保たれていなければならない
–
–
Node – 各オブジェクト
Edge – オブジェクト内のポインタ
Copy GC におけるコピー操作

1.
2.
GC の前後で、ヒープ内のオブジェクトの
グラフとしての構造が保たれていなければならない
あるオブジェクトを別の場所にコピー
コピーされたオブジェクトを指していたポインタ全て
を、GC の終了時までに、オブジェクトの新しい位置
を指すように更新
Cheney’s Breadth-first Copying
アルゴリズムとデータ構造


キューを用いた幅優先探索アルゴリズム
To_space をキューとして用いる。
–

To_space へのオブジェクトのコピーは、同時に、
オブジェクトをキューに追加することを意味する。
探索しながら、オブジェクトをコピーしていく。
Cheney’s Breadth-first Copying
データ構造


ヒープ : From_space と To_space
To_space 内を指すポインタ
–
–

scan – 次に探索されるオブジェクトを指すポインタ
キューの先頭を指すポインタ
free – To_space の空き領域の先頭を指すポインタ
キューの末尾を指すポインタ
Forwarding pointer
–
コピーされるオブジェクトの古い位置に置かれ、
新しい位置を指すポインタ。
Cheney’s Breadth-first Copying
アルゴリズム
1.
初期化 – キューを空にする

2.
3.
4.
5.
scan = free = (To_space の先頭)
ルートから指されているオブジェクトを To_space
にコピー(キューに追加)
キュー内のオブジェクトに指されているオブジェク
トをコピー(キューに追加)
以上を、キューが空になるまで続ける。
最後に、From_space と To_space を交換
Cheney’s Breadth-first Copying
アルゴリズム(オブジェクトのコピー)
object* copy(object* p)
{
if ( p is already copied) { return p->forwarding_addr; }
object* newaddr = free;
memcpy(newaddr,p,p->size);
free = free + p->size;
p->forwarding_addr = newaddr;
return newaddr;
}
Cheney’s Breadth-first Copying
アルゴリズム(オブジェクトのコピー)
From_space
ポインタの更新
From_space
To_space
To_space
scan
free
Forwarding pointer
オブジェクトのコピー
- コピー前 -
- コピー後 -
Cheney’s Breadth-first Copying
アルゴリズム(オブジェクトのコピー)
From_space
To_space
From_space
To_space
Forwarding pointer
すでにコピーされたオブジェクトを指している場合、
ポインタを forwarding pointer で置き換える
Cheney’s Breadth-first Copying
アルゴリズム(GC のメインループ)
gc(){
// 1.
foreach r in rootset { r = copy(r); } // object* r; // 2.
scan = free = (To_space の先頭);
while(scan < free){
foreach p in scan.children{ // object* p;
p = copy(p);
3.
4.
}
scan = scan + p->size;
}
swap(To_space,From_space);
}
// 5.
Bartlett’s Mostly Copying Collector
~ Compacting Garbage Collection with Ambiguous Roots~
Root set の型が分からない
状況下での Copying GC
Bartlett’s Mostly-Copying Collector


もともとScheme => C コンパイラ用に開発された。
想定している条件



Root set(レジスタ、スタック)は、曖昧なポインタとして扱う。
ヒープ内のオブジェクトの構造については、GC は
完全に知っている。
上のような条件のもとでCopy GC を実現
Conservative GC 用語

曖昧なポインタ
–
–
–

ある word について、それがポインタであるか否かがわ
からないような word
ポインタかもしれないので、「指されている」オブジェクト
は生きている可能性がある。
ポインタでないかもしれないので、書き換えるとプログラ
ムが正しく動かなくなる場合がある。
Bartlett’s Mostly-Copying GC 等では、
曖昧なポインタに「指されている」オブジェクトは、
とりあえず生かされる(Conservative GC)。
Mostly Copying Collector の概要(1)




同じサイズのページ達で構成されるヒープ
{曖昧なポインタすべて} = {Rootset のword}
GC の始めの Rootset の 探索時に、
曖昧なポインタに「指されている」オブジェクトを含む
ページを next_space に指定。
next_space 内のオブジェクトは、GC 中コピーせず、
そのままその場に残す。
Mostly Copying Collector の概要(2)

曖昧なポインタに指されているオブジェクトを含む
ページ内のオブジェクト全体を Rootset だと思って、
古典的な Copy GC を実行するのと等価
–
–

ただ、上記のようなページを、explicit に Rootset として
扱っているわけではない。
アルゴリズムが非常に簡単
キューを用いた幅優先探索アルゴリズム
Bartlett’s Mostly Copying Collector
本来の Root set
新しいRootset
内には、曖昧
なポインタが
存在しない。
普通のCopy GC が可能。
Bartlett’s Mostly-Copying Collector
データ構造

ヒープ : 同じ大きさに区切られたページより構成
–
–

キュー
–
–

– 曖昧なポインタに指されているページ
– GC 中に新しく確保されたページ
– To_space に相当
Current_space – それ以外。From_space に相当
Next_space
page 単位で管理
Next_space が連続した領域でないため、必要。
Forwarding Pointer – Copy GC と同じ
Bartlett’s Mostly-Copying Collector
Root set
キュー
Bartlett’s Mostly-Copying Collector
アルゴリズム
1.
2.
3.
初期設定 – キューを空にする
本来のルートから「指されている」オブジェクトを
含むページをnext_space に指定、キューに追加
キュー内の各ページについて
1.
4.
ページ内の各オブジェクトについて、指されているオブ
ジェクトをキューの最後のページにコピー。
以上を、キューが空になるまで続ける。
古典的 Copy GC におけるコピー操作

1.
2.
GC の前後で、ヒープ内のオブジェクトの
グラフとしての構造が保たれていなければならない
あるオブジェクトを別の場所にコピー
コピーされたオブジェクトを指していたポインタ全て
を、GC の終了時までに、オブジェクトの新しい位置
を指すように更新
Bartlett’s Mostly-Copying Collector
のコピー操作(1)

オブジェクトのコピー
–
–
–
オブジェクトが既に next_space にある場合は、コピーし
ない。
オブジェクトがまだコピーされていない場合は、
オブジェクトを キューの最後のページの最後にコピーし、
もとの位置に forwarding_pointer を残す
もし、キューの最後のページの空き領域が足りない場合、
新しいページをキューの最後に追加し、そこにコピー。
Bartlett’s Mostly-Copying Collector
のコピー操作(2)
object* copy(object* p){
if(p belongs to next_space || p == NULL){ return p; }
if(p is already copied){ return p->forwarding_addr; }
object* newobj = move(p);
p->forwarding_addr = newobj;
return newobj;
}
Bartlett’s Mostly-Copying Collector
アルゴリズム
1.
2.
3.
初期設定 – キューを空にする
本来のルートから「指されている」オブジェクトを
含むページをnext_space に指定、キューに追加
キュー内の各ページについて
1.
4.
ページ内の各オブジェクトについて、指されているオブ
ジェクトをキューの最後のページにコピー。
以上を、キューの最後まで続ける。
Bartlett’s Mostly Copying Collector
void gc(){
next_space = current_space + 1;
queue = empty;
// 1.
// 2.
foreach r in rootset{ promote_page(page pointed by r); }
while(queue is not empty){
block = queue.dequeue();
foreach obj in block{
3.
foreach q in obj.children{ q = copy (q); }
}
}
current_space = next_space:
}
4.
Bartlett’s Mostly Copying Collector
void promote_page(page* p){
if(p->spaceID == current_space){
p->spaceID = next_space;
2.
queue.enqueue(p);
}
}
Bartlett’s Mostly-Copying Collector
アルゴリズム
Root set
キュー
2. 本来のルートから「指されている」オブジェクトを含む
ページをnext_space に指定、キューに追加
Bartlett’s Mostly-Copying Collector
キュー
指されているオブジェクトを
3.
キュー内の各ページについて
1.
ページ内の各オブジェクトについて、指されているオ
ブジェクトをページキューの最後のページにコピー。
Bartlett’s Mostly-Copying Collector
キュー
指されているオブジェクトを
コピー
3.
キュー内の各ページについて
1.
ページ内の各オブジェクトについて、指されているオ
ブジェクトをページキューの最後のページにコピー。
Bartlett’s Mostly-Copying Collector
キュー
4.
以上を、キューの最後まで
続ける。
結局、何がうれしいか。

スタックやレジスタなどの、曖昧なポインタの存在の
元で、Copy GC が実現できた。
–
–

曖昧なポインタに指されていないページについて、
断片化を解消できる。
アルゴリズムが非常に単純 - 実装がラク
Root set の中にオブジェクトの中間を指すポインタ
が存在しても OK
Bartlett’s Mostly-Copying Collector
の欠点

曖昧なポインタに指されているページにあるオブ
ジェクトが生き残ってしまう。
–

さらに、その子孫まで生き残ってしまう。
曖昧なポインタに指されているページについて、
断片化が起こってないように見えるが、
実は死んでいるオブジェクトが間を埋めているだけ。
関連研究



[Appel 1988] Copying Garbage Collection in the
Presence of Ambiguous References
(http://research.microsoft.com/~drh/pubs/tr-162-88.pdf)
[Yip 1991] Incremental,Generational Mostly-Copying
Garbage Collection in Uncooperative Environments
(http://www.research.compaq.com/wrl/techreports/abstracts/91.8.html)
[田中 1998] 卒業論文,Copying Garbage Collection in the
Presence of Uncertain Pointers
(/home/yl2/y-tanaka/ise-env/work/98winter/senior-thesis/thesis)
References
[Bartlett 1988] Joel.F.Bartlett,
Compacting Garbage Collection with Ambiguous
Roots
(http://www.research.compaq.com/wrl/techreports/abstracts/88.2.html)
 Garbage Collection,Algorithm for Automatic
Dynamic Memory Management,
Richard Jones,Rafael Lins
(青い本)
