17

Boehm GCをチェックしました。C/C++ の GC。

マークアンドスイープアルゴリズムを知っています。私が興味を持っているのは、C メモリ全体でポインターのみを取得する方法です。C メモリに関する私の理解は、単純なバイト配列にすぎません。メモリ内の値がポインタであるかどうかを判断することは可能ですか?

4

1 に答える 1

20

Boehm GC は保守的なコレクターです。つまり、すべてがポインターであると想定します。これは、偶然にもヒープ内のアドレスの値を持つ整数など、偽陽性の参照を見つけることができることを意味します。その結果、一部のブロックは、非保守的なコレクターの場合よりも長くメモリに留まる可能性があります。

Boehm のページからの説明は次のとおりです。

ガベージ コレクターは、変更されたマーク スイープ アルゴリズムを使用します。概念的には、メモリ割り当ての一部として時折実行される 4 つのフェーズで動作します。

  1. 準備 各オブジェクトには関連するマーク ビットがあります。すべてのオブジェクトが潜在的に到達不能であることを示して、すべてのマーク ビットをクリアします。
  2. マーク フェーズ 変数からのポインターのチェーンを介して到達可能なすべてのオブジェクトをマークします。多くの場合、コレクターはヒープ内のポインター変数の場所に関する実際の情報を持っていないため、すべての静的データ領域、スタック、およびレジスターを潜在的にポインターを含むものとして見なします。コレクターによって管理されるヒープ オブジェクト内のアドレスを表すビット パターンは、ポインターとして表示されます。クライアント プログラムがヒープ オブジェクトのレイアウト情報をコレクターで利用できるようにしない限り、変数から到達可能であることが判明したヒープ オブジェクトはすべて、同様に再度スキャンされます。
  3. スイープ フェーズ ヒープをスキャンして、アクセスできない、つまりマークされていないオブジェクトを探し、それらを再利用できるように適切なフリー リストに戻します。これは実際には別のフェーズではありません。非インクリメンタル モードであっても、これは通常、空のフリー リストを検出する割り当て中にオンデマンドで実行される操作です。したがって、スイープ フェーズは、いずれにせよその後すぐには触れられなかったページに触れる可能性は非常に低いです。
  4. ファイナライズ フェーズ ファイナライズのために登録された到達不能オブジェクトは、コレクターの外部でファイナライズのためにキューに入れられます。

また、Boehm GC には一連の「ルート」を指定する必要があることも知っておく必要があります。これは、マーク アンド スイープ アルゴリズムの開始点です。スタックとレジスタは自動的にルートになります。グローバル ポインターをルートとして明示的に追加する必要があります。


編集: コメントでは、保守的なコレクター全般についていくつかの懸念が指摘されました。コレクターへのヒ​​ープ ポインターのように見える整数によって、メモリが解放されない可能性があることは事実です。これは、あなたが思っているほど大きな問題ではありません。プログラム内のほとんどのスカラー整数は、カウントとサイズに使用され、かなり小さいです (したがって、ヒープ ポインターのようには見えません)。ほとんどの場合、ビットマップ、文字列、浮動小数点データなどを含む配列で問題が発生します。GC_MALLOC_ATOMICBoehm GC を使用すると、ブロックにポインターが含まれないことをコレクターに示すブロックを割り当てることができます。gc_typed.hを見ると、ブロックのどの部分にポインターを含めることができるかを指定する方法も見つかります。

つまり、保守的なコレクターの基本的な制限は、ポインターの書き換えが安全ではないため、コレクション中にメモリを安全に移動できないことです。これは、断片化の減少やキャッシュ パフォーマンスの向上など、圧縮のメリットが得られないことを意味します。

于 2011-01-25T16:54:24.797 に答える