7 ガベージファースト(G1)ガベージ・コレクタ

この項では、ガベージファースト(G1)ガベージ・コレクタ(GC)について説明します。

ガベージファースト(G1)ガベージ・コレクタの概要

ガベージファースト(G1)ガベージ・コレクタは、大量のメモリーにスケーリングするマルチプロセッサ・マシンを対象としています。これはガベージ・コレクション一時停止時間目標を高い確率で満たそうとする一方、構成の必要がなく、高いスループットを実現します。G1はレイテンシとスループットの間で最適なバランスを取ることを目標とし、現在のターゲット・アプリケーションと次の機能が含まれる環境を使用します。

  • 最大で数十GBまたはそれ以上のヒープ・サイズ(Javaヒープの50%超がライブ・データで占められている)。
  • 時間が経つと大きく変化する可能性のあるオブジェクトの割当て率および昇格率。
  • ヒープ内の大量の断片化。
  • 数百ミリ秒以内の予測可能な一時停止ターゲット目標(長時間のガベージ・コレクションの一時停止を回避)。

G1は、アプリケーションの実行と同時に処理の一部を実行します。これにより、本来ならばアプリケーションで使用できるはずのプロセッサ・リソースと引き換えに、コレクションの一時停止時間が短くなります。

これは、アプリケーションの実行中に、アクティブなガベージ・コレクション・スレッドを1つ以上使用すると最もよくわかります。したがって、スループット・コレクタと比較すると、G1コレクタでは通常、ガベージ・コレクションによる一時停止時間が大幅に短い一方で、アプリケーションのスループットが若干低下する傾向もあります。

G1は、デフォルトのコレクタです。

G1コレクタは高いパフォーマンスを実現し、次の項で説明されているいくつかの方法で一時停止時間目標を満たそうとします。

G1の有効化

ガベージファースト・ガベージ・コレクタはデフォルト・コレクタであるため、通常、追加の処理を実行する必要はありません。コマンド行で-XX:+UseG1GCを指定すると、これを明示的に有効化できます。

基本概念

G1は、世代別、増分的、並列型、モーストリ・コンカレント、stop-the-world型で退避型のガベージ・コレクタであり、stop-the-world型の一時停止ごとに一時停止時間目標を監視します。他のコレクタと同様に、G1では(仮想の)若い世代と古い世代にヒープを分割します。領域の回収は若い世代に行う方が効果的であるため、若い世代に対して集中的に行われますが、古い世代に対して行われることもあります

一部の操作は常にstop-the-world型の一時停止で実行され、スループットを向上させます。グローバル・マーキングのようなヒープ全体の操作など、アプリケーションを停止すると時間がかかる他の操作は、アプリケーションと同時に並列実行されます。領域の回収でstop-the-world型の一時停止を短くするために、G1は領域回収を徐々に増分しながら並列実行します。G1では、前回のアプリケーションの動作とガベージ・コレクションの一時停止に関する情報をトラッキングして予測し、関連するコストのモデルを作成します。この情報を使用して、一時停止で実行される作業のサイズを判定します。たとえば、G1では、最も効率的な場所の領域を最初に回収します(ガベージでほぼいっぱいになっている領域を最初に行うため、このように呼ばれています)。

G1では、主に退避を使用して領域を回収します。選択したメモリー領域内で見つかったライブ・オブジェクトは新しいメモリー領域にコピーされ、プロセスでこれらを圧縮します。退避が完了すると、ライブ・オブジェクトで占有されていた領域はアプリケーションによる割当てに再使用されます。

ガベージファースト・コレクタは、リアルタイム・コレクタではありません。時間をかけて設定された一時停止時間目標を高い確率で満たそうとしますが、特定の一時停止では必ずしも絶対確実ではありません。

ヒープ・レイアウト

G1ではヒープを均等サイズのヒープ・リージョン・セットに分割し、図7-1に示すように、それぞれは連続する一連の仮想メモリーです。リージョンとは、メモリー割当ておよびメモリー回収の単位です。任意の時点で、これらの各リージョンは空であるか(明るいグレー)、特定の世代(若い世代または古い世代)に割り当てられています。メモリーに対するリクエストが届くと、メモリー・マネージャが空きリージョンを割り当てます。メモリー・マネージャはこれらを世代に割り当て、次に空き領域としてアプリケーションに返し、そこに割当てできるようにします。

図7-1 G1ガベージ・コレクタのヒープ・レイアウト

図7-1の説明が続きます
「図7-1 G1ガベージ・コレクタのヒープ・レイアウト」の説明

若い世代には、Edenリージョン(赤)とSurvivorリージョン(Sが付いた赤)が含まれています。これらのリージョンは、他のコレクタの連続的な各領域と同じ機能を備えており、G1において通常、これらのリージョンはメモリー内で連続的でないパターンで配置されている点が異なります。古いリージョン(水色)は古い世代を構成しています。古い世代のリージョンは複数のリージョンにまたがるオブジェクトに対してサイズが大きくなることがあります(Hが付いた水色)。

アプリケーションは、古い世代に属しているために直接割り当てられている大型オブジェクトを除いて、常に若い世代(Edenリージョン)に割り当てられます。

ガベージ・コレクション・サイクル

高いレベルで、G1コレクタは2つのフェーズを交代させます。若い世代のみのフェーズには、現在使用可能なメモリーを古い世代のオブジェクトで徐々に満たすガベージ・コレクションが含まれています。領域回収フェーズでは、G1は増分しながら古い世代の領域を回収し、さらに若い世代に対応します。その後、このサイクルでは若い世代のみのフェーズを再度開始します。

図7-2に、このサイクルの概要および発生する可能性のあるガベージ・コレクションの一時停止の順序の例を示します。

図7-2 ガベージ・コレクションのサイクルの概要

図7-2の説明が続きます
「図7-2 ガベージ・コレクションのサイクルの概要」の説明

次のリストに、フェーズ、一時停止、G1ガベージ・コレクション・サイクルのフェーズ間での推移を詳細に示します。

  1. 若い世代のみのフェーズ: このフェーズは、オブジェクトを古い世代に昇格させる、いくつかの通常の若い世代のコレクションから開始します。若い世代のみのフェーズと領域回収フェーズ間の推移は、古い世代の占有率が特定のしきい値(開始ヒープ占有率しきい値)に達したときに開始します。この時点で、G1は通常の若い世代のコレクションのかわりに、コンカレント開始の若い世代のコレクションをスケジュールします。 

    • コンカレント開始: このタイプのコレクションはマーキング・プロセスを開始し、通常の若い世代のコレクションも実行します。コンカレント・マーキングでは、次の領域回収フェーズで維持される、古い世代のリージョンの現在到達可能なすべての(ライブ)オブジェクトを判定します。マーキングが完全に終了していない場合、通常の若い世代のコレクションが発生することがあります。マーキングは、再マークとクリーン・アップの2つの固有のstop-the-world型の一時停止で終了します。 

      コンカレント開始の一時停止では、マーキングをたどる必要がないことも決定できます。この場合、短いコンカレント・マークの元に戻すフェーズが発生し、若い世代のみのフェーズが続行されます。この場合、再マークおよびクリーン・アップの一時停止は発生しません。

    • 再マーク: この一時停止は、マーキング自体をファイナライズし、参照処理とクラスのアップロードを実行し、空のリージョンを完全に回収して、内部データ構造をクリーン・アップします。再マークとクリーン・アップの間に、G1は、選択した古い世代のリージョン内の空き領域を後で回収できるようにする情報を同時に計算し、この情報がクリーン・アップの一時停止でファイナライズされます。

    • クリーン・アップ: この一時停止では、領域回収フェーズが実際に後に続くかどうかを判定します。領域回収フェーズが後に続いた場合、この若い世代のみのフェーズは、単一の混合準備の若い世代のコレクションで完了します。 

  2. 領域回収フェーズ: このフェーズは複数の若いコレクションから構成され、若い世代のリージョンに加えて、古い世代のリージョン・セットのライブ・オブジェクトも退避します。これらのコレクションは、混合コレクションとも呼ばれます。領域回収フェーズは、古い世代のリージョンをこれ以上退避しても、十分な空き領域を作り出せないとG1が判断した場合に終了します。

領域回収後、コレクション・サイクルが別の若い世代のみのフェーズから再度開始します。バックアップとして、アプリケーションがライブ情報の収集中にメモリーを使い果たした場合、G1では他のコレクタのようなstop-the-world型のインプレース・フル・ヒープ圧縮(フルGC)を実行します。

ガベージ・コレクションによる一時停止とコレクション・セット

G1はガベージ・コレクションと領域回収をstop-the-world型の一時停止で実行します。通常、ライブ・オブジェクトはヒープ内のソース・リージョンから1つ以上の宛先リージョンにコピーされ、これらの移動済オブジェクトへの既存の参照が調整されます。

大型リージョン以外の場合、オブジェクトの宛先リージョンは、そのオブジェクトのソース・リージョンにより決定されます。

  • 若い世代(EdenリージョンとSurvivorリージョン)のオブジェクトは、それぞれの期間に応じてSurvivorリージョンまたは古いリージョンにコピーされます。
  • 古いリージョンのオブジェクトは他の古いリージョンにコピーされます。

大型リージョン内のオブジェクトは別々に処理されます。G1は、通常、これらのオブジェクトを移動せず、そのライブ状態を判断するのみです。ライブ状態でない場合は、占有している領域を再利用します。G1では、非常に遅い最終手段の収集作業で大型オブジェクトのみが移動されます。

記憶済セット

コレクション・セットG1を退避するには、記憶済セット(コレクション・セットへの参照を含むコレクション・セット外の一連の場所)を管理します。ガベージ・コレクション中にコレクション・セットからオブジェクトが移動する場合、コレクション・セット外からそのオブジェクトへの他の参照を変更してオブジェクトの新しい場所を指すようにする必要があります。

記憶済セットのエントリは、メモリーを節約するためにおおよその場所を表します。多くの場合、近接した参照は近接したオブジェクトを参照するため、1つの記憶済セットのエントリで複数の場所をカバーします。G1は記憶済セットのエントリをカードで表します。これはヒープの小さな論理パーティションです。デフォルトでは、これらは512バイトのサイズの領域です。記憶済セットのエントリは、これらのカードの圧縮参照です。

G1は、若い世代を除き、記憶済セットをリージョンごとに管理します。通常、すべてのリージョンに独自の記憶済セットがありますが、若い世代のリージョンでは、すべての若い世代のリージョンに1つの記憶済セットが使用されます。ここには、任意の若い世代リージョンへの参照がある場所が含まれています。

記憶済セットは、主に遅延して作成されます。つまり、再マークとクリーン・アップの一時停止の間に、G1は、すべてのマーキング・コレクション・セットの候補リージョンの記憶済セットを再構築します。若い世代のリージョンはコレクションごとに収集されるため、G1は、常にそれらの記憶済セットを維持します。

コレクション・セット

コレクション・セットとは、ガベージ・コレクション時に領域を回収するソース・リージョンのセットです。コレクション・セットは、ガベージ・コレクション・タイプとは関係なく、異なる種類のリージョンで構成されます。

  • 若い世代のリージョン
  • 大型リージョン。制限については、「大型オブジェクト」を参照してください。
  • コレクション・セットの候補リージョン。これらは、収集効率が高いために、ガベージ・コレクションに適した候補リージョンであるとG1が判断した古い世代のリージョンです。

    この効率は、空き領域の量から計算されます。ライブ・データがほとんどないリージョンは、ほとんどがライブ・データを含むリージョンよりも優先され、他のリージョンとの接続性は、接続性が高いよりも低い方が優先されます。

    古い世代のコレクション・セットの候補リージョンには、2つのソースがあります。ヒープ分析全体(つまり、G1がすべての古い世代のリージョンのライブ状態と接続性に関する適切な情報を持っている場合のマーキング)と、退避の失敗が発生したリージョンです。

    前者のリージョンの効率性は、直前のコンカレント・マークで収集された最新のライブ状態および接続性のデータを使用して直接判断されています。

    退避に失敗したリージョンには、オブジェクトがほとんど含まれていないことがよくあります。そのため、これらのリージョンのガベージ・コレクションは非常に効率的です。したがって、デフォルトでコレクション・セットの候補リージョンになります。

    G1は、このガベージ・コレクションで収集する必要があるコレクション・セットの候補リージョンと、時間が許せばガベージ・コレクションされるオプションのコレクション・セットの候補リージョンを区別します。

ガベージ・コレクション・プロセス

ガベージ・コレクションは4つのフェーズで構成されます。

  • 退避前コレクション・セット・フェーズでは、ガベージ・コレクションの準備作業(ミューテータ・スレッドからのTLABの切断、「Javaヒープ・サイズの設定」で説明しているこのコレクションのコレクション・セットの選択、その他の小さな準備作業)が実行されます。

  • ヒープ・ルートのマージ中に、G1は、後でコレクション・セット・リージョンからの並列処理を容易にするために単一の統合記憶済セットを作成します。これにより、個々の記憶済セットから多数の重複が削除されます。そうしないと、後でより高コストな方法で除外する必要があります。

  • コレクション・セットの退避フェーズは、作業の大部分を表します。G1は、ルートから始まるオブジェクトの移動を開始します。ルート参照は、コレクション・セット外部(一部のVM内部データ構造(外部ルート)、コード(コード・ルート)または残りのJavaヒープ(記憶済セットによって決定されるヒープ・ルート))からの参照です。すべてのルートについて、G1は、コレクション・セット内の参照オブジェクトをその宛先にコピーし、ルートがなくなるまでその参照を新しいルートとしてコレクション・セットに処理します。

    これらのフェーズの個々のタイミングは、それぞれExt Root ScanningCode Root ScanScan Heap RootsおよびObject Copyサブフェーズの-Xlog:gc+phases=debugロギングによって観察できます。

    G1は、オプションのコレクション・セットの主な退避フェーズを繰り返すこともできます。

  • 退避後コレクション・セットは、次のミューテータ・フェーズの参照処理および設定を含むクリーン・アップ作業で構成されます。

これらのフェーズは、-Xlog:gc+phases=infoロギングで出力されるフェーズに対応します。

ガベージファーストの内部

この項では、ガベージファースト(G1)ガベージ・コレクタの重要な詳細情報について説明します。

Javaヒープ・サイズの設定

G1では、Javaヒープ・サイズを変更する際に標準ルールが考慮され、初期Javaヒープ・サイズには-XX:InitialHeapSize、最大Javaヒープ・サイズには-XX:MaxHeapSize、空きメモリーの最小割合には-XX:MinHeapFreeRatio、サイズ変更後の空きメモリーの最大割合を決定するには-XX:MaxHeapFreeRatioがそれぞれ使用されます。G1コレクタは、再マークの一時停止とフルGCの一時停止時にのみ、これらのオプションに従ってJavaヒープ・サイズを変更します。このプロセスでは、オペレーティング・システムにメモリーを解放したり、オペレーティング・システムからメモリーを割り当てたりできます。

ヒープ拡張は、ガベージ・コレクションの一時停止中に発生する可能性があります。G1がJavaヒープを縮小する必要があると判断した場合、このメモリーの解放は、一時停止後にアプリケーションと並行して行われます。

若い世代のみのフェーズの世代のサイズ設定

G1は、通常の若い世代のコレクションの終了時に、次のミューテータ・フェーズ用に若い世代の初期サイズを決定します。ミューテータ・フェーズが進むにつれて、G1は、このサイズの推定値を定期的に調整します。

-XX:GCPauseIntervalMillisおよび-XX:MaxGCPauseTimeMillisオプションは、ガベージ・コレクション・アクティビティに適合する最小ミューテータ使用率(MMU)をG1に提供します。-XX:GCPauseIntervalMillisの可能なすべての時間範囲に対して、G1は、ガベージ・コレクションの一時停止のために最大で-XX:MaxGCPauseTimeMillisミリ秒を使用するようにコレクション一時停止のサイズを設定します。この計算に使用される情報には、同様のサイズの若い世代が退避にかかった時間に関する過去の観測、コレクション時にコピーする必要があったオブジェクト数、およびこれらのオブジェクトが相互接続された方法に関する情報が含まれます。

オプション-XX:G1NewSizePercentおよび-XX:G1MaxNewSizePercentは、最小および最大のEdenサイズを制限し、ガベージ・コレクションの一時停止時間を制限します。「ガベージファースト・ガベージ・コレクタのチューニング」・ガイドでは、これらを使用して最大一時停止数を減らす方法の例をいくつか示します。

または、-XX:NewSize-XX:MaxNewSizeと組み合せて使用して、若い世代の最小サイズと最大サイズをそれぞれ設定することもできます。

通常の若いコレクションの開始時に、G1は、「コレクション・セット」の項で説明されているように、使用可能な時間に基づいて追加の古い世代リージョンを選択します。

ノート:

後者のオプションのいずれか1つを指定してEdenサイズを設定すると、若い世代のサイズは-XX:NewSizeおよび-XX:MaxNewSizeでそれぞれ渡される値に正確に固定されます。これにより、一時停止時間の制御は無効化されます。

若いコレクションの開始時に、G1は、「コレクション・セット」の項で説明されているように、使用可能な時間に基づいて追加の古い世代リージョンを選択します。

領域回収フェーズの世代のサイズ設定

領域回収フェーズ時に、G1では、1回のガベージ・コレクションの一時停止で古い世代で回収される領域の量を最大化しようとします。若い世代のサイズは、他の若い世代のみのフェーズのガベージ・コレクションと同様に決定されますが、コレクション・セットに含める古い世代リージョンの最小セットも考慮されます。

このフェーズで混合コレクションが開始されるごとに、G1は、「コレクション・セット」の項で説明されているように、リージョンからコレクション・セットを決定します。コレクション・セット内の古い世代のリージョンの量は、次のように決定されます。

  • 退避の進行を確保するための、古い世代のリージョンの最小セット。この古い世代のリージョン・セットは、マーキングによってコレクション・セットの候補として決定される古い世代のリージョン数を、領域回収フェーズの長さ(-XX:G1MixedGCCountTargetで決定)で割ることによって決まります。
  • G1が最小セットを収集した後に時間が残っていると予測した場合に、コレクション・セットの候補から追加する古い世代のリージョン。古い世代のリージョンは、残り時間の80%が使用済と予測されるまで追加されます。
  • 他の2つの部分が退避された後、今回の一時停止時間が残っている場合に、G1が徐々に退避するオプションのコレクション・セットの一連のリージョン。

G1は、初回のガベージ・コレクション・パスで最初の2つのリージョン・セットを収集し、残りの一時停止時間内に収まるように、オプションのコレクション・セットのリージョンを含む追加のコレクション・パスを取得します。この方法によって、領域回収の進行を確保しながら、一時停止時間を維持して、オプションのコレクション・セットの管理に伴うオーバーヘッドを最小限に抑えられる確率を高めることができます。

コレクション・セットの候補リージョン・セットにマーキング候補リージョンがなくなると、領域回収フェーズが終了します。

G1が使用する古い世代のリージョンの数および長い混合コレクションの一時停止を回避する方法の詳細は、「ガベージファースト・ガベージ・コレクタのチューニング」を参照してください。

定期的なガベージ・コレクション

アプリケーションがアクティブでなかったためにガベージ・コレクションが長期間実行されていない場合、他で使用できたはずの大量の未使用メモリーがVMに不必要に長期間保持されている可能性があります。これを回避するには、長いアイドル期間中に-XX:G1PeriodicGCIntervalオプションを使用して、G1で定期的なガベージ・コレクションを強制的に実行できます。このオプションでは、アイドル・アプリケーションの状態を検出した後、G1がガベージ・コレクションの実行を検討する最小間隔(ミリ秒)を指定します。前回のガベージ・コレクションによる一時停止後にこの期間が経過し、進行中のコンカレント・サイクルがない場合、G1は次のような結果を伴う追加のガベージ・コレクションをトリガーします。

  • 若い世代のみのフェーズ時: G1はコンカレント開始の一時停止を使用してコンカレント・マーキングを開始するか、-XX:-G1PeriodicGCInvokesConcurrentが指定されている場合は、フルFull GCを開始します。
  • 領域回収フェーズ時: G1は領域回収フェーズを継続し、現在の進行状況に適したガベージ・コレクションによる一時停止タイプをトリガーします。

-XX:G1PeriodicGCSystemLoadThresholdオプションを使用して、G1のアイドル状態の意味を調整する必要があります。JVMホスト・システム(コンテナなど)に対するgetloadavg()コールによって返された1分間のシステム負荷平均値がこの値を上回った場合、VMはアイドル状態とはみなされず、定期的なガベージ・コレクションは実行されません。

定期的なガベージ・コレクションの詳細は、『JEP 346: Promptly Return Unused Committed Memory from G1』を参照してください。

開始ヒープ占有率の決定

開始ヒープ占有率(IHOP)は、コンカレント開始コレクションがトリガーされるしきい値で、古い世代のサイズの割合として定義されます。

G1では、デフォルトで、マーキングにかかった時間とマーキング・サイクル時に古い世代に通常割り当てられるメモリーの量を監視することで、最適なIHOPを自動的に判定します。この機能は、適応型IHOPと呼ばれます。この機能がアクティブな場合、オプション-XX:InitiatingHeapOccupancyPercentは、開始ヒープ占有率しきい値を予測するのに十分な監視結果がなければ、現在の古い世代のサイズの割合として初期値を判定します。オプション-XX:-G1UseAdaptiveIHOPを使用して、G1のこの動作をオフにします。この場合、-XX:InitiatingHeapOccupancyPercentの値は常にこのしきい値を判定します。

内部的に、適応型IHOPは開始ヒープ占有率を設定しようとします。これにより、古い世代の占有率が現在の古い世代の最大サイズから余分なバッファとして-XX:G1HeapReservePercentの値を差し引いた値に達したときに、領域回収フェーズの最初の混合ガベージ・コレクションが開始します。

マーキング

G1マーキングでは、 Snapshot-At-The-Beginning (SATB)と呼ばれるアルゴリズムを使用します。コンカレント開始の一時停止時にヒープの仮想スナップショットを取得します。マーキングの開始時にライブだったすべてのオブジェクトは、マーキングの残りに対してライブとみなされます。これは、マーキング時に寿命を終えた(到達不能な)オブジェクトが領域回収のためにライブとしてみなされているということです(一部例外あり)。他のコレクタと比較すると、これによって追加のメモリーが不適切に保持される場合があります。ただし、SATBでは再マークの一時停止時に適切なレイテンシが発生する可能性があります。このマーキング時にライブ・オブジェクトとみなされたオブジェクトは、次回のマーキング時に回収されます。マーキングでの問題の詳細は、「ガベージファースト・ガベージ・コレクタのチューニング」のトピックを参照してください。

退避の失敗

退避の失敗は、ガベージ・コレクション中にG1が一部のオブジェクトを移動できなかったことを意味します。

このような状況は、Evacuation Failure: <reason>という出力で-Xlog:gcロギングによるガベージ・コレクション・ログに示されます。<reason>は、次の例に示すように、AllocationPinnedのいずれかまたは両方です:

[9,740s][info ][gc] GC(26) Pause Young (Normal) (G1 Evacuation Pause) (Evacuation Failure: Allocation/Pinned) 2159M->402M(3000M) 6,108ms

  • Allocation: G1は、オブジェクトの移動先の宛先領域に十分な領域を見つけられませんでした。
  • Pinned: G1が、GetPrimitiveArrayCritical()または類似のJNIコールを使用してネイティブ・コードを安全に使用できるように、所定の位置にロックされている、つまり固定されているオブジェクトを検出したため、G1が移動できなかったオブジェクトがあります。オブジェクトの固定の詳細は、JEP 423: G1の領域固定に関する項を参照してください。

G1がすべてのオブジェクトをリージョンから移動できない場合、そのリージョンは一時的に割当てできなくなります。G1は、これらのリージョンを、コレクション・セットの候補として、次のガベージ・コレクションで即時退避するようにスケジュールします。

最悪の場合、ガベージ・コレクション中にガベージ・コレクションで領域がまったく解放されない場合、G1はフルGCをスケジュールします。このタイプのガベージ・コレクションは、ヒープ全体のインプレース圧縮を実行します。これは時間がかかることがあります。

割当ての失敗またはメモリーからの通知の前のフルGCの問題の詳細は、「ガベージファースト・ガベージ・コレクタのチューニング」を参照してください。

大型オブジェクト

大型オブジェクトとは、リージョンの半分のサイズ以上のオブジェクトです。「G1 GCのエルゴノミック・デフォルト」の項で記述されているように、-XX:G1HeapRegionSizeオプションを使用して設定されないかぎり、現在のリージョン・サイズはエルゴノミックに決定されます。

これらの大型オブジェクトは次のように扱われることがあります。
  • すべての大型オブジェクトは、古い世代の連続的なリージョンの順序に従って割り当てられます。オブジェクト自体の開始は、常に、最初のリージョンの開始時にその順序で行われます。オブジェクト全体が回収されるまで、順序内の最後のリージョンで残っている領域が割当てのために失われます。
  • 一般的に、大型オブジェクトは到達不能になった場合、再マークの一時停止中またはフルGC中のマーキングの終了時にのみ回収できます。ただし、プリミティブなタイプの配列(たとえば、bool、すべての種類の整数、浮動小数点の値)の大型オブジェクト用に特殊なプロビジョニングがあります。G1では、大型オブジェクトがガベージ・コレクションの一時停止で多数のオブジェクトから参照されなくなった場合、大型オブジェクトを回収しようとします。この動作はデフォルトで有効になっていますが、オプション-XX:-G1EagerReclaimHumongousObjectsを指定すると無効化できます。
  • 大型オブジェクトの割当てによってガベージ・コレクションの一時停止が早く発生することがあります。G1は、大型オブジェクトの割当てごとに開始ヒープ占有率しきい値をチェックし、現在の占有率がしきい値を超え、現在進行中のマーキングがない場合に、即座にコンカレント開始の若い世代のコレクションを強制できます。
  • 大型オブジェクトは、最初のフルGCで十分な連続メモリーを解放できず、同じ一時停止中の2回目のフルGCで別の大型オブジェクトを割り当てることができない場合に、最終手段としてのコレクションでのみ移動されます。このプロセスは非常に低速です。大型オブジェクトの終わりを含むヒープ・リージョンに、割当てに使用できる領域がないため、G1はメモリー不足の状態でVMを終了する可能性があります。

G1 GCのエルゴノミック・デフォルト

このトピックでは、G1に固有の重要なデフォルト設定とそのデフォルト値の概要について説明します。追加のオプションを指定せずにG1を使用して想定される動作およびリソースの使用状況の概要についても説明します。

表7-1 G1 GCのエルゴノミック・デフォルト

オプションとデフォルト値 説明

-XX:MaxGCPauseMillis=200

最大一時停止時間の目標。

-XX:GCPauseTimeInterval=<ergo>

最大一時停止時間間隔の目標。デフォルトではG1は目標を設定せず、極端な場合にガベージ・コレクションを連続的に実行します。

-XX:ParallelGCThreads=<ergo>

ガベージ・コレクションの一時停止時に並行作業に使用するスレッドの最大数。これは、VMが実行されるコンピュータの使用可能なスレッド数から導出されます。たとえば、プロセスに使用可能なCPUスレッド数が8以下の場合、これを使用します。これ以外の場合、最終スレッド数よりも大きいスレッドの8分の5を追加します。

一時停止ごとに開始時に使用されるスレッドの最大数は最大合計ヒープ・サイズによってさらに制限されます。つまり、G1が -XX:HeapSizePerGCThread単位当たりのJavaヒープ容量に対して使用できるスレッドは1つのみです。

-XX:ConcGCThreads=<ergo> 

並行作業に使用されるスレッドの最大数。デフォルトでは、この値は-XX:ParallelGCThreads を4で割った値です。

-XX:+G1UseAdaptiveIHOP

-XX:InitiatingHeapOccupancyPercent=45

開始ヒープ占有率を制御するデフォルトは、その値の適応的な決定がオンになっていて、マーク開始のしきい値として、最初のいくつかのコレクション・サイクルでG1が古い世代の45%の占有率を使用していることを示します。

-XX:G1HeapRegionSize=<ergo> 

ヒープ領域のサイズ。デフォルト値は最大ヒープ・サイズに基づいており、これは約2048リージョンをレンダリングするように計算され、人間工学的に決定される最大値は32MBです。ユーザーが指定したサイズは2の累乗である必要があり、有効な値の範囲は1から512 MBです。

-XX:G1NewSizePercent=5

-XX:G1MaxNewSizePercent=60

若い世代の合計サイズは、使用中の現在のJavaヒープの割合であるため、これらの2つの値で変化します。

-XX:G1HeapWastePercent=5

現在の合計ヒープ・サイズの割合として、ヒープ内で許容される回収されない領域。G1は、これらのリージョンの収集後の合計空き領域がその値より小さい場合、マーキング・コレクション・セット候補への古い世代のリージョンの追加を停止します。

-XX:G1MixedGCCountTarget=8

多数のコレクション内での領域回収フェーズの想定される長さ。

-XX:G1MixedGCLiveThresholdPercent=85

この割合より高い占有率のライブ・オブジェクトを含む古い世代のリージョンは、領域回収フェーズで収集されません。

ノート:

<ergo>は、実際の値が環境によってエルゴノミックに決定されるという意味です。

古い世代からの大きな空のオブジェクトの回収は、常に有効になっています。オプション-XX:-G1EagerReclaimHumongousObjectsを指定すると、この機能を無効化できます。デフォルトで、文字列の重複除外は無効になっています。オプション-XX:+G1EnableStringDeduplicationを使用して有効にできます。

他のコレクタとの比較

これは、G1と他のコレクタとの主な相違点のサマリーです。

  • パラレルGCは、全体として古い世代の領域を圧縮および回収できます。G1では、複数のより短いコレクション間でこの作業を分散します。これにより、一時停止時間が短縮されますがスループットが犠牲になる可能性があります。
  • G1では古い世代の領域回収の一部を同時に実行します。
  • G1では、前述のコレクタよりも高いオーバーヘッドを示し、この同時性のためにスループットに影響を及ぼす場合があります。
  • ZGCは、スループットをさらに犠牲にして、一時停止時間を大幅に短縮することを目指しています。

動作方法のために、G1はガベージ・コレクションの効率性を向上させるメカニズムを備えています。

  • G1は、任意のコレクション中に一部の大型オブジェクトを再利用可能です。これによって、多くの不要なガベージ・コレクションを回避して、大量の領域を容易に解放できます。
  • オプションで、G1は同時にJavaヒープで文字列の重複を除外できます。

古い世代からの大きな空のオブジェクトの回収は、常に有効になっています。オプション-XX:-G1EagerReclaimHumongousObjectsを指定すると、この機能を無効化できます。デフォルトで、文字列の重複除外は無効になっています。オプション -XX:+G1EnableStringDeduplicationを使用すると、これを有効化できます。