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

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

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

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

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

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

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

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

記憶済セットのエントリは、メモリーを保存するおおよその場所を表します。多くの場合、近くにまとまっている参照は近くにまとまっているオブジェクトを参照します。G1は、ヒープをカードに論理的にパーティション化します(デフォルトでは512バイトのサイズの領域)。記憶済セットのエントリは、これらのカードの圧縮型索引です。

G1は、最初にこの記憶済セットをリージョンごとに管理します。すべてのリージョンには、リージョンごとの記憶済セット、このリージョンへの潜在的な参照を持つ場所のセットが含まれます。ガベージ・コレクション時に、コレクション・セット全体に対する記憶済セットがそれらから生成されます。

記憶済セットは、主に遅延して作成されます。つまり、再マークとクリーン・アップの一時停止の間に、G1は、すべてのコレクション・セットの候補リージョンの記憶済セットを再構築します。それ以外にG1は、すべてのコレクションで収集される若い世代のリージョン用の記憶済セットと、デフォルトで、即時回収のために一部の大型オブジェクトを維持します。

コレクション・セット

コレクション・セットとは、領域の回収元であるソース・リージョンのセットです。ガベージ・コレクションのタイプによって、コレクション・セットを構成するリージョンの種類は異なります。

  • 若い世代のみのフェーズのコレクション・セットは、若い世代のリージョンと、回収できる可能性のあるオブジェクトが含まれている大型リージョンのみで構成されます。
  • 領域回収フェーズのコレクション・セットは、若い世代のリージョン、回収できる可能性のあるオブジェクトが含まれている大型リージョン、およびコレクション・セットの候補リージョンの一部の古い世代のリージョンで構成されます。

コレクション・セットの候補リージョンは、領域回収フェーズで収集される可能性が高いリージョンです。G1は、含まれるライブ・データ量と他のリージョンとの接続性に応じて、再マークの一時停止中にそれらを選択します。ライブ・データがほとんどない(空き領域が多い)リージョンは、ほとんどがライブであるリージョンや接続性の低いリージョンよりも優先されます。より効率的なこれらのリージョンを収集する方が手間が小さいためです。G1は、コレクション・セットの候補リージョンから空きメモリーの利益にあまり寄与しないリージョンを削除します。これには、回収可能な領域の量が現在のヒープ・サイズの-XX:G1HeapWastePercent%未満であるすべてのリージョンが含まれます。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は、通常の若い世代のコレクションの終了時に、次のミューテータ・フェーズ用に若い世代のサイズを決定します。このように、G1は、実際の一時停止時間の長時間に及ぶ監視に基づいて、-XX:MaxGCPauseTimeMillis-XX:GCPauseIntervalMillisを使用して設定された一時停止時間目標を満たすことができます。この計算では、同様のサイズの若い世代が退避するのにどのくらい時間がかかるかを考慮します。これには、コレクション時にコピーする必要があったオブジェクト数やこれらのオブジェクトが相互接続された方法などの情報が含まれます。

-XX:GCPauseIntervalMillisおよび-XX:MaxGCPauseTimeMillisオプションは、最小ミューテータ使用率(MMU)を定義します。G1は、-XX:GCPauseIntervalMillisの可能なすべての時間範囲に対して、ガベージ・コレクションの一時停止に最大で-XX:MaxGCPauseTimeMillisミリ秒の使用を試みます。

制限がなければ、G1は、-XX:G1NewSizePercent-XX:G1MaxNewSizePercentが一時停止時間を満たすために決定する値の間で適応させながら若い世代のサイズを決定します。長い一時停止を修正する方法の詳細は、「ガベージファースト・ガベージ・コレクタのチューニング」を参照してください。

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

ノート:

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

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

領域回収フェーズ時に、G1では、1回のガベージ・コレクションの一時停止で古い世代で回収される領域の量を最大化しようとします。若い世代のサイズは通常最小許容値に設定され、通常は-XX:G1NewSizePercentによって決まりますが、MMU仕様も考慮されます。

このフェーズで混合コレクションが開始されるごとに、G1はコレクション・セットの候補から一連のリージョンを選択して、コレクション・セットに追加します。この追加する古い世代のリージョン・セットは次の3つの部分で構成されます。

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

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

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

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

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

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

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

-XX:G1PeriodicGCSystemLoadThresholdオプションを使用すると、ガベージ・コレクションをトリガーするかどうか調整できます。JVMホスト・システム(コンテナなど)に対するgetloadavg()コールによって返された1分間のシステム負荷平均値がこの値を上回った場合、定期的なガベージ・コレクションは実行されません。

定期的なガベージ・コレクションの詳細は、『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で、まだ移動していないオブジェクトをコピーせずに、すでに新しい場所に移動したオブジェクトを保持して現在のガベージ・コレクションを完了しようとしており、オブジェクト間の参照のみを調整していることを意味します。退避が失敗すると、追加のオーバーヘッドが発生することがありますが、一般的に他の若いコレクションと速度は変わりません。退避が失敗したガベージ・コレクションの後で、G1はアプリケーションを通常どおりに再開し、他の措置は取りません。G1では、退避の失敗はガベージ・コレクションの終了間際に発生すると想定しています。すなわち、ほとんどのオブジェクトはすでに移動していて、マーキングが完了して領域の回収が開始するまで、アプリケーションの実行を続けるのに十分な領域が残っているということです。

この想定が当てはまらない場合、G1は最終的にフルGCをスケジュールします。このタイプのコレクションは、ヒープ全体のインプレース圧縮を実行します。これは時間がかかることがあります。

G1は、予防的な若いコレクションをスケジュールすることで、若いコレクション中の退避の失敗を回避しようとします。このようなガベージ・コレクションのオーバーヘッドをまったく発生させないように大型リージョンを回収することで、退避障害を発生させない追加の定期的な若いコレクションが、古い世代で十分なメモリーを解放できることを想定しています。-XX:-UsePreventiveGCオプションを使用して、予防的な若いコレクションをオフにできます。

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

大型オブジェクト

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

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

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リージョンをレンダリングするように計算され、人間工学的に決定される最大値は32 MBです。ユーザーが指定したサイズは2の累乗である必要があり、有効な値の範囲は1から512 MBです。

-XX:G1NewSizePercent=5

-XX:G1MaxNewSizePercent=60

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

-XX:G1HeapWastePercent=5

コレクション・セットの候補内の許容される回収されない領域の割合。コレクション・セットの候補内の空き領域がこれより低い場合、G1は領域回収フェーズを停止します。

-XX:G1MixedGCCountTarget=8

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

-XX:G1MixedGCLiveThresholdPercent=85

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

ノート:

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

他のコレクタとの比較

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

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

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

  • G1では、コレクション時に古い世代の大きな空の領域を完全に回収できます。これは、多くの不要なガベージ・コレクションを回避して、大量の領域を容易に解放できます。
  • オプションで、G1は同時にJavaヒープで文字列の重複を除外できます。

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