[JVMの深い理解] G1ガベージコレクター

G1コレクターは、サーバー側で実行されるガベージコレクターであり、特にマルチコアプロセッサと大容量メモリを搭載したマシン用です。JDK7u4バージョンのリリース時に正式にリリースされ、JDK9の公式GCコレクターとして指定されました。可能な限り短いGC休止時間を満たしながら、高スループットを満たします。G1コレクターは、次のアプリケーションシナリオ向けに特別に設計されています

  • CMSコレクターのようにアプリケーションと同時に実行できます
  • 長いGCポーズを必要とせずに、空きメモリフラグメントを圧縮します
  • GCの一時停止についてより適切な予測を行うことができます
  • スループットパフォーマンスを大幅に犠牲にしたくない
  • より大きなJavaヒープは必要ありません

長期計画から、G1はCMSに取って代わることを目指しています。CMSと比較すると、G1をGCのより良いソリューションにするいくつかの違いがあります。

  • 最初のポイント:G1は空きメモリを圧縮して十分にコンパクトにします。アプローチは、メモリの断片化を減らすために、割り当てにきめ細かい空きリストの代わりに領域を使用することです。
  • 2番目のポイント:G1のSTWはより制御可能です。G1は一時停止時間に予測メカニズムを追加し、ユーザーは希望の一時停止時間を指定できます。

1.なぜG1を学ぶのか

JVMの最新のガベージコレクターであるG1(Garbadge First Collector)は、CMSのコンカレントモード障害の問題を解決し、超大容量ヒープの処理の一時停止を最小限に抑え、G1でのガベージコレクション中のメモリ圧縮を完了して、メモリフラグメントの生成を減らすことができます。 。G1は、ヒープメモリが比較的大きい場合に比較的高いスループットと短い一時停止時間を示し、Java9のデフォルトのコレクターになりました。将来的にCMSを置き換えるのは時間の問題です。

2.G1のGC原理

G1では、ヒープは同じサイズのヒープ領域(通常は2,000以上)に分割され、これらの領域は論理的に連続しています。各地域には、固有の世代マーク(エデン、サバイバー、オールド)が付けられます。論理的には、エデン領域はエデン空間を構成し、サバイバー領域はサバイバー空間を構成し、古い領域は古い空間を構成します。

コマンドラインパラメーターを使用-XX:NewRatio=nして、新世代と旧世代の比率を構成します。デフォルトは2、つまり比率は2:1です-XX:SurvivorRatio=n。EdenとSurvivorの比率を構成でき、デフォルトは8です。

GC中のG1の動作モードは、CMSの動作モードと似ています。ヒープ内のオブジェクトの存続を判断するために、同時グローバルマーキングフェーズプロセスがあります。同時マーキングが完了すると、G1は、どの領域に空き領域が多いか(再利用可能なオブジェクトが多いか)を認識し、これらの空の領域を優先的に再利用して、大量の空き領域を解放します。これが、このガベージコレクションメソッドがG1(ガベージファースト)と呼ばれる理由です。

G1は、リサイクル可能なオブジェクト(つまりゴミ)でいっぱいになる可能性のあるヒープ内の領域に収集および圧縮アクティビティを集中し、一時停止予測モデルを使用してユーザー定義の一時停止時間の目標を達成し、収集する領域の数を指定された一時停止時間の目標。

G1はリアルタイムコレクターではないことに注意してください。設定された一時停止時間の目標を高い確率で達成できますが、完全に確実というわけではありません。G1は、以前に収集されたデータに基づいて、ユーザーが指定した目標時間内に収集できる領域の数を推定します。したがって、コレクターは、収集領域のコストのかなり正確なモデルを持っており、このモデルを使用して、一時停止時間の目標内に収集する領域と領域の数を決定します。

2.1G1の地域

G1の各リージョンのサイズは固定されており、同じです。リージョンのサイズは、パラメーター-XX:G1HeapRegionSizeで設定でき、値の範囲は1Mから32Mで、指数は2です。設定されていない場合、G1はヒープサイズに従って自動的に決定されます。

決定ロジック:

size =(堆最小值+堆最大值)/ TARGET_REGION_NUMBER(2048) ,然后size取最靠近2的幂次数值, 并将size控制在[1M,32M]之间。

G1のメモリ構造は、従来のメモリ空間分割とはかなり異なります。G1は、メモリを同じサイズの複数の領域(デフォルトは512K)に分割し、領域は論理的に連続しており、物理メモリアドレスは連続していません。同時に、各リージョンはE、S、O、Hとしてマークされ、それぞれEden、Survivor、Old、およびHumongousを表します。その中で、EとSは若い世代に属し、OとHは古い世代に属します。
概略図は次のとおりです。

 

  • HはHumongousの略です。文字通り、大きなオブジェクト(以下、Hオブジェクトと呼びます)を表すと理解できます。割り当てられたオブジェクトがRegionサイズの半分以上の場合、それは巨大なオブジェクトと見なされます。Hオブジェクトはデフォルトで旧世代に割り当てられるため、GC中の大きなオブジェクトのメモリコピーを防ぐことができます。ヒープメモリがHオブジェクトを収容できないことが判明した場合、GC操作がトリガーされます。

2.2世代間の参照

Young GCの間、Young領域のオブジェクトはまだOld領域への参照を持っている可能性があります。これは世代間の参照の問題ですYoung GCの問題を解決し、老後全体をスキャンするために、G1はCard Table合計Remember Set概念を導入しました。基本的な考え方は、時間のためにスペースを使用することです。これらの2つのデータ構造は、特にOld領域からYoung領域への参照を処理するために使用されます。ヤングエリアからオールドエリアへの参照は、ヤングエリア内のオブジェクト自体が大幅に変更されているため、個別に処理する必要はありません。したがって、それらを記録するためにスペースを無駄にする必要はありません。

  • RSet:このリージョンへのすべての外部参照を記録するために使用されるフルネームの記憶セット。各リージョンはRSetを維持します。
  • カード:JVMはメモリを固定サイズのカードに分割します。これは、物理メモリ上のページの概念に類似している可能性があります。

RS(Remember Set)は、非コレクション部分からコレクション部分へのポインターのコレクションを記録するために使用される抽象的な概念です。
従来の世代別ガベージコレクションアルゴリズムでは、RS(Remember Set)を使用して世代間のポインターを記録します。G1コレクターでは、RSは、他のリージョンからリージョンへのポインターを記録するために使用されます。したがって、1つのリージョンに1つのRSがあります。この種の記録には大きなメリットがあります。リージョンを再利用する場合、ヒープ全体のスキャンを実行する必要はありません。RSをチェックするだけで外部参照を見つけることができます。これらの参照は、初期のルートの1つです。マーク。

次に、スレッドがリージョン内の参照を変更する場合、レコードを変更するようにRSに通知する必要があります。この目標を達成するために、G1リサイクラーは新しい構造であるCT(カードテーブル)-カードテーブルを導入しました。各地域は、固定サイズの複数のカード(カード)に分割されています。各カードはバイトを使用して、変更されたかどうかを記録します。カードテーブルは、これらのバイトのコレクションです。実際、RSが概念モデルとして理解されている場合、CTはRSの実装であると言えます。

RSの変更でも、並行性の問題が発生します。リージョンは複数のスレッドによって同時に変更される可能性があるため、RSも同時に変更されます。このような競合を回避するために、G1ガベージコレクターはRSをさらに複数のハッシュテーブルに分割します。各スレッドは、独自のハッシュテーブルで変更されます。最終的に、論理的に言えば、RSはこれらのハッシュテーブルのコレクションです。ハッシュテーブルは、RSを実装する通常の方法の1つです。重複を取り除くことができるという大きな利点があります。これは、RSのサイズが変更されたポインターの数と同じになることを意味します。重複排除がない場合、RSの数は書き込み操作の数と同じになります。

図中のRSの破線の表の名前は、RSがカード表とは別個の異なるデータ構造ではなく、概念モデルとしてRSを参照していることです。実際、カードテーブルはRSの実装です。RSet構造の保守については、この記事を参照してください。ここではあまり詳しく説明しません。

2.3 SATB

SATB(snapshot-at-the-beginning)は、元々リアルタイムのガベージコレクターに使用されていたテクノロジーです。G1ガベージコレクターは、このテクノロジーを使用して、マーキングフェーズでライブオブジェクトのスナップショットを記録します(「マーキングサイクルの開始時に、ヒープ内のライブオブジェクトのセットのスナップショットを論理的に取得します」)。ただし、同時マーキングフェーズでは、アプリケーションは元の参照を削除するなど、元の参照を変更する場合があります。これにより、同時マーキングの終了後のライブオブジェクトのスナップショットがSATBと矛盾するようになります。G1は、同時マーキングフェーズに書き込みバリアを導入することでこの問題を解決します。参照の更新がある場合は常に、G1は変更前の値をログバッファに書き込みます(このレコードは元のnull参照を除外します)。SATBをスキャンします。 SATBエラーを修正するための最終マーキングフェーズ。
まず、3色マーキングアルゴリズムを紹介します。

  • 黒:ルートオブジェクト、またはオブジェクトとその子オブジェクトがスキャンされます
  • 灰色:オブジェクト自体はスキャンされていますが、オブジェクト内のサブオブジェクトはまだスキャンされていません
  • 白:スキャンされていないオブジェクトすべてのオブジェクトをスキャンした後、最終的な白のオブジェクトは到達不能オブジェクト、つまりガベージオブジェクトになります。

(1)3色マーキング方式GCルートのスキャンプロセスは次のとおりです。

  • GCスキャンCの前の色は次のとおりです。

  • 同時マーキングフェーズでは、アプリケーションスレッドがこの参照関係を変更します
A.c=C
B.c=null

以下の結果が得られます。

  • 再マーキングフェーズでのスキャン結果は次のとおりです。

この場合、Cはゴミとして収集されます。スナップショットの存続オブジェクトは元々A、B、およびCでしたが、現在はAおよびBになっています。スナップショットの整合性が破壊されています。明らかに、このアプローチは不合理です。
G1が使用するのは、pre-write barrier(写屏障)この問題解決することです。簡単に言えば、同時マーキングフェーズでは、参照関係が変更されると、pre-write barrier関数はこの変更を記録し、JVMソースコードで呼び出されるキューに保存しますsatb_mark_queueリマークフェーズでは、キューがスキャンされます。このようにして、古い参照が指すオブジェクトがマークされ、その子孫も再帰的にマークされるため、オブジェクトが失われることはなく、スナップショットの整合性はまた、それは保証されています。

3.G1のGCモード

3.1若いGC

若いGCは、若い世代のすべての地域を開拓します。Eエリアが新しいオブジェクトを割り当てることができなくなったときにトリガーされますエリアEのオブジェクトはエリアSに移動されます。エリアSのスペースが十分でない場合、エリアEのオブジェクトはエリアOに直接昇格され、エリアSのデータは新しいエリアSに移動されます。エリアSの一部のオブジェクトが特定の年齢に達すると、エリアOに昇格します。
YungGCプロセスの概略図は次のとおりです。

(1)YGCは老後全体をスキャンする必要がありますか?

オブジェクトが生きているかどうかの判断は、GC ROOTSノードから開始する必要があり、GCROOTSノードから到達可能なオブジェクトは生きていることがわかっています。YGCでは、旧世代のオブジェクトは収集されません。つまり、旧世代のオブジェクトはGCROOTSに含まれている必要があります。ただし、老後全体をスキャンするには時間がかかり、必然的にGC全体のパフォーマンスに影響します。したがって、カードテーブルの構造は、旧世代から新世代への参照を記録するCMSで使用されます。カードテーブルの構造は連続したbyte []配列です。カードテーブルをスキャンする時間は、老後全体をスキャンするコストよりもはるかに短いです。G1もこのアイデアを参照していますが、新しいデータ構造、Remembered Set、または略してRsetを採用しています。RSetは、このリージョン内のオブジェクトを参照する他のリージョン内のオブジェクト間の関係を記録し、points-into構造(オブジェクトを参照する)に属します。カードテーブルはポイントアウト(そのオブジェクトを参照します)であり、各カードは特定の範囲のヒープ(通常は512バイト)をカバーします。G1のRSetは、カードテーブルに基づいて実装されます。各リージョンは、他のリージョンがそれ自体へのポインターを持っていることを記録し、これらのポインターが含まれるカードの範囲をマークします。このRSetは実際にはハッシュテーブルであり、Keyは他のリージョンの開始アドレスであり、Valueはセットであり、内部の要素はカードテーブルのインデックスです。各リージョンには、対応するRsetがあります。

RSetはGCをどのように支援しますか?YGCを実行する場合、ルートセットとして若い世代のリージョンのRSetを選択するだけで済みます。これらのRSセットは、古い世代全体をスキャンすることを避けて、古い->若い世代間の参照を記録します。gcを混合すると、古い->古いRSetが古い世代で記録され、若い->古い参照はすべての若い世代の領域をスキャンすることによって取得されるため、すべての古い世代の領域をスキャンする必要はありません。したがって、RSetの導入により、GCの作業負荷が大幅に軽減されます。

したがって、G1のYGCは古い世代全体をスキャンする必要はなく、Rsetをスキャンするだけで、新しい世代のどのオブジェクトが古い世代によって参照されているかを知ることができます。

3.2混合GC

G1のMIXGCは、新世代のすべての地域に加えて、グローバル同時マーキング統計に基づいて収集収益の高い旧世代の地域をいくつか選択し、コスト内でリサイクルするために可能な限り収益の高い旧世代の地域を選択しますユーザーが指定したターゲット範囲。したがって、MIXGCによって回収されるメモリ領域は、若い世代+古い世代です。

MIXGCを導入する前に、グローバル同時マーキング、グローバル同時マーキングを理解する必要があります。古い世代のリサイクルはこのプロセスに依存しているからです。
1.グローバル同時マーキング(グローバル同時マーキング)
グローバル同時マーキングは、さらに次の手順に細分化できます。

  • 初期マーク(STW)初期マークはSTWイベントであり、完了した作業は、GCROOTSから直接到達可能なオブジェクトにマークを付けることです。そして、それらのフィールドをマーキングスタックにプッシュし、次のスキャンまで待ちます。G1は、オブジェクトヘッダーのマークワードでマークビットを使用する代わりに、外部ビットマップを使用してマーク情報を記録します。STWのため、YGCは通常YGCのSTWを使用して初期マークを開始します。つまり、YGCから論理的に独立したグローバル同時マーキングを開始します。
  • ルート領域スキャン:ルート領域スキャンは、サバイバーエリアのオブジェクトから開始され、古い時代のオブジェクトにマークを付け、次のスキャンまでフィールドをマーキングスタックにプッシュします。初期マークとは異なり、ルート領域スキャンでは、STWをアプリケーションと同時に実行する必要はありません。YGCを開始する前に、ルート領域スキャンを完了する必要があります。
  • 同時マーキングSTWは必要ありません。スキャンスタックから参照を常にフェッチして、ヒープ全体のオブジェクトを再帰的にスキャンします。オブジェクトがスキャンされるたびにマークが付けられ、そのフィールドがスキャンスタックにプッシュされます。スキャンスタックが空になるまで、スキャンプロセスを繰り返します。その過程で、SATB書き込みバリアによって記録された参照もスキャンされます。同時マーキングはYGCによって中断される可能性があります
  • 最終マーク(備考、STW)STW操作。同時実行マーキングが完了すると、各Javaスレッドには、まだ処理されていないSATB書き込みバリア(書き込みバリア)レコード参照が残ります。この段階では、残りの参照を処理します。同時に、この段階で弱参照処理(参照処理)も実行されます。この一時停止とCMSのリマークには本質的な違いがあることに注意してください。つまり、この一時停止はSATBバッファをスキャンするだけでよく、CMSのリマークはmod-unionテーブルとルート全体のダーティカードを再スキャンする必要があります。セットされ、この時点で、若い世代全体(オブジェクトが死んでいるか生きているかに関係なく)がルートコレクションの一部と見なされるため、CMSの発言は非常に遅くなる可能性があります。
  • クリーンアップ(STWの一部)STW操作、存続オブジェクトのあるリージョンと存続オブジェクトのないリージョン(空のリージョン)のカウント、STW操作、Rsetの更新、並行操作、空のリージョンを割り当て可能なリージョンキューに収集します。

グローバル同時マーキングの後、コレクターはどの領域にオブジェクトが残っているかを認識します。そして、それらの完全にリサイクル可能なリージョンを(オブジェクトを存続させずに)収集し、それらを割り当て可能なリージョンキューに追加して、メモリのこの部分のリサイクルを実現します。オブジェクトが残っているリージョンの場合、G1は、統計モデルに従ってオブジェクトを再利用するためにユーザーが指定した上限を超えない、収益とコストが最も高いリージョンを見つけます。これらの選択されリサイクルされたリージョンのコレクションは、コレクションセット、または略してCsetと呼ばれます。

  • MIXGCのCsetは、若い世代のすべての地域に加えて、グローバルな同時マーキング統計に基づいて収集収益の高いいくつかの古い世代の地域を選択することです。
  • YGCのCsetは、若い世代のすべての地域を選択することです。若いGCのコストは、若い世代の地域の数を制御することによって制御されます。
  • YGCとMIXGCはどちらも、マルチスレッドレプリケーションを使用してクリアし、プロセス全体がSTWになります。G1の低遅延の原則は、再生領域が正確になり、範囲が狭くなることです。

2.ライブオブジェクトのコピー(退避)
退避フェーズは完全に中断されます。リージョン内のライブオブジェクトの一部を空のリージョンにコピーし(並列コピー)、元のリージョンスペースを再利用します。避難フェーズでは、任意の数のリージョンを自由に選択して、コレクションセット(コレクションセット、略してCSet)を個別に収集および形成できます。CSetコレクションでのリージョンの選択は、上記の一時停止予測モデルによって異なります。この段階すべての生物を避難させるわけではありません。避難する収益の高い少数の地域のみを選択すると、この停止のオーバーヘッドを(特定の範囲内で)制御できます。

混合GCの洗浄プロセスの概略図は次のとおりです。

3.2フルGC

G1のガベージコレクションプロセスは、アプリケーションと同時に実行されます。混合GCの速度がメモリのアプリケーションの速度に追いつかない場合、混合G1はシリアルGCを使用してフルGCにダウングレードされます。フルGCは長期的なSTWを引き起こしますが、これは可能な限り回避する必要があります。
G1フルGCには2つの理由が考えられます。

  1. 避難中にプロモートされたオブジェクトを格納するのに十分なスペースがありません。
  2. 並行処理が完了する前にスペースが不足しています

4.動作原理

最高レベルから見ると、G1のコレクター側は実際には2つの主要な部分です。

  • グローバル同時マーキング(グローバル同時マーキング)
  • サバイバルオブジェクト(避難)コピーすると、これら2つの部分は比較的独立して実行できます。

4.1 グローバル同時マーキング(グローバル同時マーキング)

グローバル同時マーキングは、SATB形式の同時マーキングに基づいています。それは次の段階に分けられます:

  • 初期マーキング(初期マーキング)一時停止フェーズルートセットをスキャンし、ルートセットから直接到達可能なすべてのオブジェクトにマークを付け、次のスキャンまでフィールドをマーキングスタックにプッシュします。G1は、オブジェクトヘッダーのマークワードでマークビットを使用する代わりに、外部ビットマップを使用してマーク情報を記録します。世代別G1モードでは、最初のマーキングフェーズは若いGCの一時停止を借用するため、追加の個別の一時停止フェーズはありません。
  • 同時マーキング(同時マーキング)同時フェーズスキャンスタックから参照を常にフェッチして、ヒープ全体のオブジェクトグラフを再帰的にスキャンします。オブジェクトがスキャンされるたびにマークが付けられ、そのフィールドがスキャンスタックにプッシュされます。スキャンスタックが空になるまで、スキャンプロセスを繰り返します。このプロセスでは、SATB書き込みバリアによって記録された参照もスキャンされます。
  • 最終マーキング(最終マーキング、実装ではリマーキングとも呼ばれます)一時停止フェーズ同時実行マーキングが完了すると、各Javaスレッドには、処理されていないSATB書き込みバリア(書き込みバリア)レコード参照が残ります。この段階では、残りの参照を処理します。同時に、この段階で弱参照処理(参照処理)も実行されます。
    この一時停止とCMSのリマークには本質的な違いがあることに注意してください。つまり、この一時停止はSATBバッファをスキャンするだけでよく、CMSのリマークはmod-unionテーブルとルート全体のダーティカードを再スキャンする必要があります。セットされ、この時点で、若い世代全体(オブジェクトが死んでいるか生きているかに関係なく)がルートコレクションの一部と見なされるため、CMSの発言は非常に遅くなる可能性があります。
  • クリーンアップ一時停止フェーズインベントリとリセットフラグのステータス。このステージは、マークスイープのスイープステージに少し似ていますが、ヒープ上の実際のオブジェクトをスイープする代わりに、マーキングビットマップで各領域が生存としてマークされているオブジェクトの数をカウントします。この段階で、ライブオブジェクトがまったくないリージョンが見つかった場合は、割り当て可能なリージョンのリストに全体として再利用されます。

世代別G1モードでCSetを選択するには、若いGCと混合GCに対応する2つのサブモードがあります。

  • 若いGC:若い世代のすべての地域を選択します。若いGCのコストは、若い世代の地域の数を制御することによって制御されます。
  • 混合GCグローバル同時マーキング統計に基づいて、若い世代のすべての地域に加えて、収集収益の高い古い世代の地域をいくつか選択します。ユーザーが指定したコスト目標範囲内で、可能な限り収益の高い旧世代の地域を選択します。

 

関連記事

  1. ガベージファースト(G1)ガベージコレクタ 

 

 

 

おすすめ

転載: blog.csdn.net/qq_41893274/article/details/113901839