3

複数のスレッドまたはプロセスで構成されるプログラムでガベージ コレクションを実行するにはどうすればよいですか?

これらのスレッドとプロセスのそれぞれからスタックをスキャンするにはどうすればよいですか?

各プロセスには独自のガベージ コレクション ルーチンが必要ですか? 実際のプログラムとは別のスレッド/プロセスでガベージ コレクターを実行するのは良い考えですか?

4

5 に答える 5

8

アドレス空間ごとに 1 回収集する必要があります。複数のスレッドが同じアドレス空間で実行されるため、それを処理する 1 つの GC が必要です。それぞれが独自のアドレス空間で実行されるさまざまなプロセスを生成することによって機能するプログラムの場合、プロセスごとに GC が存在する可能性があります。

マルチスレッドの場合、GC を別のスレッドとして実行するのが理にかなっています。そうすれば、そのスレッドの優先順位をいじって、プログラム全体の動作をほぼスムーズにすることができます。シングルスレッド プロセスの場合、「通常の」メモリ管理ルーチン (特に割り当て) にフックする GC を持つのが最も簡単ですが、2 つのスレッド (元のプロセス用の 1 つのスレッドと GC スレッド) を持つことができます。 、再び、セミスムーズなパフォーマンスを確保します。

ストップ・ザ・ワールド・コレクターは最も単純なもので、マーク・アンド・スイープ、マーク・アンド・コンパクト、ストップ・アンド・コピーなどがあります。シングル スレッド プログラムのメモリ管理ルーチンにフックする GC は、本質的にストップ ザ ワールドです。マルチスレッドの場合、スレッド スケジューラによって GC スレッドに特別な特権を与えることができます (実行することを決定したら、中断できないようにします)。これにより、そのような特権スレッドからストップ ザ ワールド GC を実行できます。

ミューテーター (つまり、プログラムの残りの部分) によって GC が中断される可能性がある場合、特に特別な処理をまったく受けない別のスレッドであるため、ミューテーターの干渉を処理できる GC が必要になります。この場合、インクリメンタル GC を見ています。IGC は、シングル スレッドのメモリ管理ルーチンへのフック セットアップで使用できます。この場合、システム全体の操作がある程度スムーズになるように、タイムアウトによって中断される場合があります。また、実行時間を他のスレッドと単純に競合するマルチスレッド システムでも使用できます。

プログラムまたはプログラムのすべてのスレッドのスタックを見つける方法はわかりませんが、これらの構造のレイアウトはオペレーティング システムごとに文書化する必要があります。Boehm GC を取得し、ソースをスキャンしてヒントを探すのは理にかなっているかもしれません。

Jones/Lins が出荷されている間は、http://www.memorymanagement.org/をご覧ください。さらに詳しい情報については、Charly Martin が上で述べたように、Sun の人々は、IBM Jikes RVM チームのメンバーや関係者と同様に、ガベージ コレクションの分野で驚くべき研究開発を行っています。

編集: チャーリー・マーティンへのコメントを読んだ後、もっと簡潔なアドバイスをさせてください: Boem GC をシステムに接続して、それで完了です。ガベージコレクタを書くのは簡単です。正しく、効率的で、高速で、適切に動作し、適切に調整され、堅牢なガベージ コレクタを作成することはほぼ不可能です。既存の GC を使用して、プロジェクトの興味深い部分に進みます。GC で行き詰まらないでください。または、さらに悪いことに、GC の実装が不十分で、あなたを際限なく悩ませることになります。

于 2008-12-28T22:54:07.140 に答える
7

ほとんどの GC はいわゆる「ストップ ザ ワールド」GC です。いくつかの事前定義されたポイント (「GC ポイント」 - コール ポイント、ジャンプ、リターンなど) で、各スレッドは GC サイクルを実行したい他のスレッドが存在するかどうかを確認します。 . すべてのスレッドが停止すると、GC サイクルが実行されます。

もちろん、他の可能性もあります - リアルタイム、インクリメンタル、コンカレント (およびその他の) GC も存在します - Web を検索するか (ほとんどの場合、公開された論文を見つけることができます)、単にGC に関する本を購入するだけです

スタック スキャンに関しては、いくつかの方法があります。

  • 正確なスキャン:

    • タグ付きスタック - 基本的に 2 つのスタックを保持します - 1 つは値を持ち、もう 1 つは「タグ」を持ちます。どのタグが必要かによって異なりますが、ほとんどの場合、「参照されている」/「参照されていない」マークになります。

    • タグのないスタック - 基本的に、厳密な型を持つ言語を使用している場合、すべての時点で (ただし、より一般的にはすべての「GC ポイント」で) スタック上の型が何であるかを知ることができます。簡単なインタープリターで使用する例を示します (私が作成したものです)。

no-return function XY (int):
 load_param 1 
 ipush 1
 iadd
 call Z (assume: int function Z (int, int))
 new some_object
 call Y

GC ポイントを call/new と定義すると、スタック タイプを知る必要があるポイントがおそらく 3 つあります (XY 関数のエントリでは、スタックは「空」と見なされます)。

  • Z を呼び出す - load_param は int パラメータをロードし、ipush は int - 2 つの int をスタックにプッシュします。
  • new - スタックから 2 つの整数を使用して Z を呼び出し、int を配置します
  • Y を呼び出す - 新たに参照を配置したので、int と参照ができたので、GC はその参照について知る必要があります。

関数のエントリでスタックが「空」であると言ったことに注意してください-実際にはそうではありませんが、すべての関数を個別に分析し、「コールスタック」を上に移動するだけです(リターンポインターがどこかにあるので、どこにあるかがわかります)リターンする必要があります - return-1 は、スタックのイメージも取得できる呼び出しです。トップに到達するまで繰り返します)。

この情報を記憶する方法は 2 つあります (タグなしスタックの場合)。

  • GC ポイントごとにテーブルを生成する
  • 各 GC ポイントのコード フラグメントを生成します (コード フラグメント自体が参照オブジェクトをマークします)。

この情報をいつ収集するかについては、事前にコンパイルするか、ジャスト イン タイムにすることができます。

これはマシン スタックにも適用できますが、レジスタも追跡する必要がある場合があるため、少し複雑になります。

タグレススタックに関するいくつかの優れた論文もオンラインで見つけることができるはずです。

たとえば、追加する場所にはさらに変更があります。データへの「活性」情報 (わかりました、スタックに参照がありますが、それを使用する命令ストリームにコードがない場合は、到達不能として扱うことができます)

  • 保守的なコレクション(正確なスキャンとは対照的に)-「この値はスタック上にあり、ポインター、参照として解釈されますか」と自問します。そうであれば、それは「生きている」です。これはもちろん、たとえば漏れる可能性があります。ポインタのように見える整数 (整数が変更されるとメモリは解放されますが、永久にリークする可能性もあります)。ほとんどの c/c++ コレクターはこの方法で実装されているため、興味がある場合はその方向で検索してください。

各プロセスには独自のガベージ コレクション ルーチンが必要ですか?

これを必要とするものは何もありませんが、一般的だと思います。簡単にするために、プロセスごとに異なる GC インスタンス (ただし、すべてのスレッドに対して 1 つだけ) を使用します。プロセス間に共有メモリアロケータがある可能性があると思います-私が見る唯一の利点は、メモリの断片化をより適切に管理できる可能性があることです(より多くのメモリを制御するため)が、複雑さ(通信/同期を相互処理する-うん)、共有データの量独立性の欠如が問題になります。私はここで推測していますが、この種の GC を実際に使用した経験はありません (または存在していたとしても) - 私には常識のように思えます。

実際のプログラムとは別のスレッド/プロセスでガベージ コレクターを実行するのは良い考えですか?

まあ、それは依存します。別のスレッドに保持することをお勧めしますが、これによって何が得られるかによって異なります-GCをシンプルに保ちますか(「世界を止める」-他のすべてのスレッドは一時停止されるため、どのスレッドで GC を実行するか、それが独自のスレッドを持っている場合はより適切です)、または特別な要件がありますか (例: スレッドはリアルタイムであり、長時間停止してはならない場合、別の GC を使用することになります)。スレッド化し、リアルタイム/インクリメンタル GC アルゴリズムを使用します)。

それはすべて必要なものに依存しますが、何をするにしても、覚えておいてください - できるだけシンプルにしてください.

そして、私はほとんど忘れていました。独自の GC をゼロから作成する代わりに、いくつかの優れた方法があります。LLVMを参照してください。彼らは、「これらのツールを活用することで、わずか 100 行ほどの C++ コードでランタイムの正確な型のスタック マップを簡単に出力できる」と主張しています。(プリコンパイルされたコードのみ、jet の時点ではコード JIT 生成はサポートされていません)。また、いくつかの Java VM のコードをいくつか見てみるとよいでしょう (たとえば、phoneME Advanced VM (CVM) と kaffe は、私が覚えている限りではかなり読みやすいです)。

免責事項: 私はかつて (学生プロジェクトとして) 正確で、世界を止める、タグのないマーク & スイープ GC を実装しました。ベストプラクティス」。修正は大歓迎です。

于 2008-12-28T21:21:55.797 に答える
2

なぜ独自のGC を実行したいのですか? それとも、GC 全般について学ぼうとしているだけですか? Hrvoje が推奨する Jones と Lin の本は非常に優れており、Wikipediaの記事も悪くありません。

1.4.2 以降の Java は、「世界を止める」停止を強制しないインクリメンタル ハイブリッド GC を提供しています。たとえば、Java ME の世界でデバイス指向の Java を扱うために、これを行う必要がありました。Sun Java の Web サイトには、かなり優れた詳細な論文があります。

于 2008-12-28T22:00:25.703 に答える
1

Java や .NET など、ほとんどすべての GC 環境では、ガベージ コレクション中にすべてのスレッドが停止します。

于 2008-12-28T21:12:07.657 に答える
1

Maoni Stephensのブログはこちらです。彼女は現在、.Net GC の主な開発者です。

その場合に .Net GC がどのように機能するかについて説明している同時 GC に関する投稿を次に示します。

于 2008-12-28T22:12:31.700 に答える