gc.h ファイルをインクルードします。
その後、
プログラム中の以下のメモリ関数を
Boehm GC ライブラリのものに
置き換えて下さい。
 
  | 元の関数 | 
  置き換える関数 | 
 
 
  | malloc | 
  GC_malloc | 
 
 
  | calloc | 
  GC_calloc | 
 
 
  | realloc | 
  GC_realloc | 
 
 
  | free | 
  消去 | 
 
修正を加えたプログラムが 
tree2.c です。
-lgcオプションを加えてコンパイルしましょう。
gcc -o tree2 tree2.c -lgc
元のプログラムに対して、
修正を行うのが嫌なら
以下のようなヘッダーファイルを用意するのが
よいでしょう。
#include <gc.h>
#define malloc  GC_malloc
#define calloc  GC_calloc
#define realloc GC_realloc
#define free
これで元のプログラムは Boehm GC を
使うように変更できました。
これでおしまいです。
その他の基本機能
Boehm GC の基本機能として、
malloc 系の関数の置き換え関数以外に、
以下のような関数が存在する。
 
 - void GC_gcollect(void)
  - 明示的に GC を発生させる関数。
     プログラムのフェーズの変わり目などに
     この関数を呼ぶことで、
     Boehm GC が管理している領域のクリーンナップが
     可能になる。
     
  - size_t GC_size(GC_PTR object_addr)
  - GC_malloc などの関数で確保したメモリ領域の
     サイズを返す関数。
     Boehm GC はメモリ割り付け時に、
     領域のサイズの大きさをメモリ領域にかきこんでおくので、
     それを読み取ってくる関数である。
     当然、
     obj_addr は
     Boehm GC によって割り付けられた
     メモリ領域の先頭アドレスである必要がある。
     
char* p = (char*)GC_malloc(1000);
size = GC_size(p);  /* GC_size は 1000 を返す。*/
     
  - GC_PTR GC_base(GC_PTR displaced_pointer)
  - この関数は、 
     構造体や配列のような大きなサイズのオブジェクトがあり、
     displaced_pointerが
     その内部のアドレスを指している時、
     オブジェクトの先頭アドレスを返してくれる関数である。
char *p, *q, *r 
p = (char*)GC_malloc(1000);
q = p + index ;
r = GC_base(q);  /* r は p と等しくなる。*/
     displaced_pointerは
     Boehm GC によって割り付けられ、
     まだ回収されていないオブジェクトの内部を指す必要がある。
     この関数は、
     常に先頭アドレスを見つけられるとは限らない。
     分からない場合には、0 を返してくる。
     また、Boehm GC によって管理されていない領域のポインタを、
     displaced_pointerにセットして渡し場合、
     エラーが発生する危険性がある。
     
  - GC_PTR GC_malloc_uncollectable(size_t size_in_bytes)
  - この関数は Boehm GC の管理している領域に、
     GC によって回収されないメモリ領域を陽にとることが
     できる。
     この関数で割り当てたオブジェクトは GC_free で回収する
     必要がある。
     
  - void GC_free(GC_PTR object_addr)
  - Boehm GC が割り当てたオブジェクトを
     明示的に解放する関数。
     主として GC_malloc_uncollectable で割り当てた
     オブジェクトを回収する。
     object_addrで指定できるのは、
     Boehm GC によって割り付けられたオブジェクトのみで、
     でたらめなアドレスや malloc/calloc によって取ってきた
     オブジェクトを指定されると、
     エラーとなる可能性がある。
     GC_free(0)の場合、
     何も操作をしない(安全性は保証されている)。
 
GC の動作状況を知る
 
サンプルプログラムは何の出力も行いませんでしたから、
本当に GC が行われたのかどうか釈然としません。
GC が行われたことをきちんと確かめましょう。
gc.hに定義されているGC_gc_noは、
Boehm GC ライブラリが起動してから何回 GC を
起こしたのかをカウントする変数です。
GC_gc_no は gc.h の中で
以下のように定義されています。
GC_word は unsigned longの
別名となっています。
//typedef unsigned long GC_word;
GC_word  GC_gc_no;
サンプルプログラムのメインループの繰り返しに、
GC_gc_no を表示するコードを
挿入してみました。
for(i = 0; i<100 ; i++){
  Tree* root = generate_tree(100);
  printf("GC counts: %d\n", GC_gc_no );
}
GC 回数以外に、
Boehm GC が管理しているメモリのパラメータを知ることが可能です。
 
  | 関数 | 
  解説 | 
 
 
  | size_t GC_get_heap_size(void) | 
  (Boehm GC が管理する)ヒープ領域の大きさサイズ | 
 
 
  | size_t GC_get_free_bytes(void) | 
  (同)ヒープ領域中の空き領域 | 
 
 
  | size_t GC_get_bytes_since_gc(void) | 
  最後の GC が起きてから割り付けたオブジェクトのサイズ | 
 
 
  | size_t GC_get_total_bytes(void) | 
  プロセスが起動してから割り付けたオブジェクトの総サイズ | 
 
tree3.cは、
サンプルプログラムを GC の状況を報告するように
修正したものです。
この方法は、プログラム内部から Boehm GC の状況を
知ることができるのですが、
Java の -verbose:gc 表示のように、
GC が起こる度に状況を報告して欲しい場合があります。
Boehm GC では、
ライブラリコンパイル時にこの機能がオフになっています。
Makefile の中のコンパイラにあたえるマクロ定義 DEFS 
の中にある -DSILENT を削除してビルドすることによって、
この機能に対応します。
# DEFS = ...  -DSILENT=1 ...
DEFS = ...   ...
SILENTマクロを外してビルドしたライブラリを使うと、
GC が起こる度に大量の内部状況を出力するようになります。
--> Marking for collection 11 after 9007104 allocd bytes + 49152 wasted bytes
Collection 10 reclaimed 8192 bytes ---> heapsize = 20586496 bytes
World-stopped marking took 210 msecs
Bytes recovered before sweep - f.l. count = 0
Immediately reclaimed 8192 bytes in heap of size 20586496 bytes
16384 (atomic) + 20561920 (composite) collectable bytes in use
Finalize + initiate sweep took 0 + 0 msecs
Complete collection took 220 msecs
Increasing heap size by 6864896 after 4096 allocated bytes
Increasing heap size by 8388608 after 6864896 allocated bytes
Initiating full world-stop collection 12 after 15253504 allocd bytes
4096 bytes in heap blacklisted for interior pointers
この出力情報は詳細で、GC に掛かった時間やメモリサイズ等の情報を得ること
ができます。
ただし、この出力がいつも出ていると鬱陶しいので
プログラムの適当な箇所で GC_quietに 0 以外の値を代入すること停止させましょう。
停止した GC 出力は、GC_quiet を 0 にすることで再開することもできます。
戻る
Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp