C プログラムでは Boehm GC はどのように機能しますか?
-
24-10-2019 - |
質問
ベームGCを調べてみました。C/C++ の GC。
私はマークアンドスイープアルゴリズムを知っています。私が興味があるのは、C メモリ全体からポインタのみをどのように取得するかということです。C メモリについての私の理解は、単なる単純なバイト配列です。メモリ内の値がポインタであるかどうかを判断することはできますか?
解決
Boehm GC は保守的なコレクターです。つまり、すべてがポインターであると想定します。これは、ヒープ内にアドレスの値が偶然含まれる整数など、誤検知の参照が見つかる可能性があることを意味します。その結果、一部のブロックは非保守的コレクターの場合よりも長くメモリ内に留まる可能性があります。
以下からの説明です ベームさんのページ:
ガベージコレクタは、変更された マークスイープアルゴリズム。概念的には 大まかに4つのフェーズで動作し、 の一部として時折実行されます。 メモリ割り当て:
- 準備 各オブジェクトには、関連付けられたマーク ビットがあります。すべてのマークをクリア bits は、すべてのオブジェクトが 到達不能の可能性があります。
- マークフェーズ のチェーンを介して到達可能なすべてのオブジェクトをマークします 変数からのポインター。多くの場合、 コレクターには実際の情報がありません ポインタの位置について 変数をヒープに格納するため、すべての 静的データ域、スタック、および 潜在的に ポインター。任意のビットパターンは、 ヒープ内のアドレスを表す コレクターによって管理されるオブジェクトは、 ポインタとして表示されます。クライアントが プログラムがヒープオブジェクトのレイアウトを作成しました 利用可能な情報 collector の場合、ヒープ オブジェクトは 変数から到達可能になり、再び 同様にスキャンされます。
- スイープフェーズ ヒープをスキャンして、アクセスできない、つまりマークされていないヒープをスキャンします。 オブジェクトを呼び出し、それらを 再利用のための適切なフリーリスト。これ は実際には別のフェーズではありません。さえ 非インクリメンタルモードでは、これは 操作は通常、 配賦中の需要は、 空のフリー・リストを検出します。したがって、 スイープフェーズが接触する可能性は非常に低いです そうではなかったであろうページ とにかくその後すぐに触れました。
- ファイナライズフェーズ 登録されていた到達不能なオブジェクト ファイナライズは、 コレクターの外部でのファイナライズ。
また、ベーム GC には、マーク アンド スイープ アルゴリズムの開始点となる一連の「ルート」を与える必要があることも知っておく必要があります。スタックとレジスタは自動的にルートになります。グローバル ポインターをルートとして明示的に追加する必要があります。
編集:コメントでは、保守的なコレクター全般についていくつかの懸念が指摘されました。確かに、コレクタへのヒープ ポインタのように見える整数によってメモリが解放されなくなる可能性があります。これはあなたが思っているほど大きな問題ではありません。プログラム内のほとんどのスカラー整数はカウントとサイズに使用され、かなり小さいです (したがって、ヒープ ポインターのようには見えません)。ビットマップ、文字列、浮動小数点データ、またはその類のものを含む配列で問題が発生することがほとんどです。Boehm GC を使用すると、ブロックを次のように割り当てることができます。 GC_MALLOC_ATOMIC
これは、ブロックにポインターが含まれないことをコレクターに示します。覗いてみると gc_typed.h, では、ブロックのどの部分にポインターを含めることができるかを指定する方法も説明します。
そうは言っても、保守的なコレクタの基本的な制限は、ポインタの書き換えが安全ではないため、コレクション中にメモリを安全に移動できないことです。これは、断片化の低下やキャッシュ パフォーマンスの向上など、圧縮による利点が得られないことを意味します。