Leopardの発売から1カ月半が経過した。Objective-C 2.0に深く切り込みたいものとしては、Mac OS X 10.5であるDarwin 9.0に搭載されているObjective-Cランタイムのソースコード公開を待ち望んでいるのだが、なかなかその気配は訪れない。

ただ待っているだけでは仕方ないので、手持ちの材料だけでObjective-C 2.0を探っていくことにしよう。Appleから公開されているドキュメントと、Mac OS X 10.4であるDarwin 8.10で公開されているソースコードを参考にしていく。

ガベージコレクタの実体とそのソースコード

では、前回の続きでガベージコレクションを探っていこう。

本連載としては、まずソースコードレベルから話を始めたかったのだが、前述のとおりLeopardではまだソースコードが公開されていない。

だがよく考えると、ガベージコレクションの機能自体は、Tigerで実装されていることを思い出した。たとえば、TigerのXcodeでビルドの設定を調べると、「Objective-Cガベージコレクションを有効にする」という項目がある。

このように、ガベージコレクタ自体は実装されていた。ただし、Cocoaなどのフレームワークが対応していなかったため、使用することは事実上できなかったのだが。

そこで、TigerのObjective-Cランタイムのソースコードをあたってみよう。Darwin 8系の最新であるDarwin 8.10に搭載されている、objc4-274のソースコードを見てみる。すると、objc-auto.mというファイルがある。これが、Objective-Cランタイムでのガベージコレクションを担当しているものになる。

このファイルには、objc_collectという関数がある。ガベージコレクションを開始するトリガーとなるものだ。そのソースコードを見てみよう。

objc-auto.m

void objc_collect(void) 
{
    if (UseGC) {
        auto_collect(gc_zone, AUTO_COLLECTION_FULL_COLLECTION, NULL);
    }
}

auto_collectという関数を呼んでいる。この関数の実体はどこにあるのか?

実は、auto_collectはObjective-Cランタイムの機能では、ない。libautoという、ランタイムとは別の、外部のライブラリに含まれる関数だ。このlibautoライブラリが、ガベージコレクションを実現している。Objective-Cランタイムは、このライブラリの1クライアントという立場になる。libautoは、/usr/lib/libauto.dylibにある※。

※このlibautoとObjective-Cランタイムとの関係は、Appleのドキュメント「Garbage Collection Programming Guide: Architecture」にも記述されている。

では、libautoのソースコードは公開されているかというと、Darwinの状況や、objc-auto.mに書かれているコメントから判断するに、オープンソースではないようだ。

という訳で、ガベージコレクタの実体がlibautoにあることはわかったが、そのソースコードは得られないようだ。

ガベージコレクタの統計的情報

とはいっても、objc-auto.mのソースコードからわかることもいくつかある。たとえば、autostatisticstという構造体の定義がある。これは、libautoで使われているもののようだ。

objc-auto.m

typedef struct {
    unsigned    version; // reserved - 0 for now
    /* Memory usage */
    unsigned long long  num_allocs; // number of allocations performed
    volatile unsigned   blocks_in_use;// number of pointers in use
    unsigned    bytes_in_use;       // sum of the sizes of all pointers in use
    unsigned    max_bytes_in_use;   // high water mark
    unsigned    bytes_allocated;
    /* GC stats */
    /* When there is an array, 0 stands for full collection, 1 for generational */
    unsigned    num_collections[2];
    boolean_t   last_collection_was_generational;
    unsigned    bytes_in_use_after_last_collection[2];
    unsigned    bytes_allocated_after_last_collection[2];
    unsigned    bytes_freed_during_last_collection[2];
    auto_date_t duration_last_collection[2];
    auto_date_t duration_all_collections[2];
} auto_statistics_t;

libautoが管理するオブジェクトの統計的情報を表すもののようだ。メモリの使用状況や、ガベージコレクション発動後の状況が得られるようだ。この構造体の値は、libautoに含まれる関数、auto_collection_statisticsなどを使えば取得できるようだ。

これらの情報も使いながら、ガベージコレクションの動作を探っていきたい。