2

私が知る限り、CMS コレクターは古い世代を収集し、ParNew コレクター (若い世代の収集に適用されます) と連携して動作します。CMSがどのように機能するかを明確に理解するのは簡単ではありませんが、私が見た方法は次のとおりです。

1) イニシャルマーク。ルート参照を探しています。コレクターは oldgen コレクターであるため、古い世代のみをスキャンする必要があります。

2) コンカレント マーク すべてのルート参照が見つかったら、コンカレント マーキングを開始します。最初のフェーズでマークされたオブジェクトから推移的に到達可能なすべてのオブジェクトは、このフェーズでマークされます。

3) コンカレント プレクリーン GC は、前のコンカレント マーキング フェーズでコンカレント マーキングを行っている間に、若い世代または新しい割り当てからの昇格によって更新された、またはミューテータによって更新された CMS ヒープ内のオブジェクトを調べます。[ 1 このフェーズの唯一の目的は、次のフェーズで実行する必要があるジョブの一部を作成することであることを確認してください(コメント) ? 2) Concurrent-Mark フェーズでどの参照が変更されたかを調べるプロセスがいくつかあります。この2つの項目について、私が正しいかどうか教えてください]

4) GC は世界を停止し、CMS ヒープ内のオブジェクトを調べます。これらのオブジェクトは、若い世代または新しい割り当てからの昇格によって更新されたか、同時プリクリーンの実行中にミューテーターによって更新されました。

でも今日、こんな記事を見た

初期マーク 初期マーク中、CMS はすべてのルート参照を収集して、古いスペースのマークを開始する必要があります。これには、スレッド スタックからの参照、若い空間からの参照が含まれます。通常、スタックからの参照は非常に迅速に (1 ミリ秒未満) 収集されますが、若いスペースから参照を収集する時間は、若いスペース内のオブジェクトのサイズによって異なります。通常、初期マークは若いスペース コレクションの直後に開始されるため、Eden スペースは空で、生存オブジェクトのみが生存スペースの 1 つになります。通常、サバイバー領域は小さく、若い領域の収集後の初期マークはミリ秒未満であることがよくあります。しかし、Eden がいっぱいになったときに初期マークが開始されると、かなり時間がかかる場合があります (通常、若いスペース コレクション自体よりも長くなります)。CMS コレクションがトリガーされると、JVM は初期のマーキングを開始する前に、若いコレクションが発生するまでしばらく待機する場合があります。JVM 構成オプション –XX:CMSWaitDuration= を使用して、CMS が初期マーキングの開始前に若い領域の収集を待機する時間を設定できます。初期マーキングの長い一時停止を回避したい場合は、この時間をアプリケーションの若いコレクションの一般的な期間よりも長く構成する必要があります。

備考ほとんどのマーキングはアプリケーションと並行して行われますが、アプリケーションはマーキング中にオブジェクト グラフを変更する可能性があるため、正確ではない可能性があります。同時採点が終了したら、ガベージ コレクターは、アプリケーションを停止し、到達可能なすべてのオブジェクトが生きているとマークされていることを確認するために、マークを繰り返す必要があります。ただし、コレクターはオブジェクト グラフ全体をトラバースする必要はありません。マーキングの開始以降に変更された参照のみをトラバースする必要があります(実際には、プレクリーンフェーズの開始以降)。カード テーブル (カード マーキング ライト バリアを参照) は、古い領域のメモリの変更された部分を識別するために使用されますが、スレッド スタックと若い領域はもう一度スキャンする必要があります。 通常、発言フェーズのほとんどの時間は、若いスペースのスキャンに費やされます。発言開始前に若いスペースにゴミを集めておけば、この時間はかなり短くなります。CMS リマークの前に常に若いスペースのコレクションを強制するように JVM に指示できます。このオプションを有効にするには、JVM パラメータ –XX:+CMSScavengeBeforeRemark を使用します。若いスペースが空であっても、リマーク フェーズは古いスペースの変更された参照をスキャンする必要があります。これには通常、通常の若いコレクションの一時停止に近い時間がかかります (若いコレクション中に行われる古いスペースのスキャンは、リマークに必要なスキャンに似ているため)。

http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots_02.html

CMS が若い世代をスキャンする必要がある理由がわかりません。なぜ古い世代のガベージコレクションに必要なのですか?

4

2 に答える 2

2

たとえば、クラス A がクラス B への参照を持ち、B が A への後方参照を持っているとします。これらのクラスに属し、相互に参照するオブジェクト a と b がある場合、gc はそれらを削除する必要があります。 「外部」からそれらへの最後の参照を削除したとき。もちろん、より多くの要素を含む参照ループでは、状況はさらに複雑になる可能性があります。そのため、gc は、あるルートから到達可能な要素と、参照されているが到達できない要素を確認する必要があり、それらを収集する必要があります。

持っている場合は、コードのどこかに

Object a=new A(new B(new C(new D())))

コンストラクターは、a が割り当てられるまでに時間がかかる場合があります。しかし、C のコンストラクターの実行に時間がかかり、aまだ割り当てられていないという理由だけで、gc が新しく作成された D を削除することは望ましくありません。そのため、ヒープから参照するには若すぎるオブジェクトをキャッチするために、若い世代もスキャンする必要があります。

于 2013-12-20T17:55:57.270 に答える
2

Java ヒープは、個別に収集される 2 つの部分に分割されます: 古い領域と若い領域です。

いずれかのスペースを収集するには、スペース外のすべてのインバウンド参照を見つける必要があります。彼らです:

  • スタックからのローカル変数
  • JIT コンパイル済みコード blob に埋め込まれたリテラル
  • 別のスペースからのすべての参照

古いコレクションが若い空間をスキャンする必要があり、若いコレクションが古い空間をスキャンする必要があることに違いはありません。

カード テーブルの書き込みバリアは、各若いコレクションの古い領域全体をスキャンしないために使用されます (古い領域のごく一部のみが若いコレクションへのリンクを含み、書き込みバリアはこの領域を追跡するのに役立ちます)。

ただし、若いスペース用のカード テーブルがないため、古いコレクションはメモリ範囲全体をスキャンする必要があります。

PS 私はあなたが参照した記事の著者です。私のブログで GC 関連の記事をいくつか見つけることができます。

于 2013-12-21T07:42:52.763 に答える