この項では、評価、分析およびパフォーマンスのためにガベージファースト・ガベージ・コレクタ(G1 GC)を適応してチューニングする方法を説明します。
「ガベージファースト・ガベージ・コレクタ」の項で説明したように、G1 GCはリージョン単位の世代別ガベージ・コレクタであり、そこではJavaオブジェクト・ヒープ(ヒープ)が多数の均等サイズのリージョンに分割されます。Java仮想マシン(JVM)では、起動時にリージョン・サイズが設定されます。リージョン・サイズは、ヒープ・サイズに応じて1MBから32MBになる場合があります。リージョンを2048個以内に抑えるためです。Eden、Survivorおよび古い世代は、これらのリージョンの論理セットであり、連続していません。
G1 GCには、満たそうとする一時停止時間目標(ソフト・リアルタイム目標)があります。若いコレクションでは、G1 GCはその若い世代(EdenのサイズとSurvivorのサイズ)を調整して、ソフト・リアルタイム目標を満たします。G1 GCが一時停止を行う理由と、一時停止時間目標の設定方法の詳細は、「ガベージファースト・ガベージ・コレクタ」の「一時停止」および「一時停止時間目標」を参照してください。
混合コレクションでは、G1 GCは混合ガベージ・コレクションの目標回数、ヒープの各リージョン内のライブ・オブジェクトの割合、およびヒープの未使用領域全体の許容割合に基づいて、収集される古いリージョンの数を調整します。
G1 GCは、ライブ・オブジェクトを1つ以上のリージョン・セット(コレクション・セット(CSet)と呼ばれる)から1つ以上の別の新しいリージョンにインクリメンタル・パラレル・コピー方式で圧縮することにより、ヒープの断片化を減らします。これにより、一時停止時間目標(ガベージファースト)を超えないように努めながら、最も再生可能な領域を含むリージョンから開始して、できるだけ多くのヒープ領域を回収します。
G1 GCでは、個別の記憶集合(RSet)を使用して、リージョンへの参照を追跡します。個別のRSetを使用すると、そのリージョンへの参照のスキャンが必要になるのはヒープ全体ではなくリージョンのRSetだけになるので、リージョンのコレクションを並列かつ個別に実行できるようになります。G1 GCでは、ポストライト・バリアを使用してヒープの変更を記録し、RSetを更新します。
stop-the-world (STW)型の若いガベージ・コレクションと混合ガベージ・コレクションで構成される退避の一時停止(「ガベージファースト・ガベージ・コレクタ」の「割当て(退避)の失敗」を参照)以外にも、G1 GCにはパラレル、コンカレントおよびマルチフェーズの各種マーキング・サイクルがあります。G1 GCはsnapshot-at-the-beginning (SATB)アルゴリズムを使用して、マーキング・サイクルの開始時にヒープ内のライブ・オブジェクト・セットのスナップショットを論理的に取得します。ライブ・オブジェクトのセットには、マーキング・サイクルの開始以降に割り当てられたオブジェクトも含まれます。G1 GCのマーキング・アルゴリズムでは、プレライト・バリアを使用して論理スナップショットに含まれるオブジェクトの記録とマーキングを行います。
G1 GCは、リージョンのEdenセットに追加されたリージョンからの割当て要求のほとんどを満たします。若いガベージ・コレクションでは、G1 GCは前回のガベージ・コレクションからEdenリージョンとSurvivorリージョンの両方を収集します。EdenリージョンとSurvivorリージョンからのライブ・オブジェクトは、新しいリージョン・セットにコピーまたは退避されます。個々のオブジェクトの移動先リージョンはオブジェクトの年齢に応じて異なります。十分な年齢に達したオブジェクトは古い世代のリージョンに退避(昇格)されます。それ以外のオブジェクトはSurvivorリージョンに退避され、次の若いガベージ・コレクションまたは混合ガベージ・コレクションのCSetに含まれます。
コンカレント・マーキング・サイクルが正常に完了すると、G1 GCは若いガベージ・コレクションの実行から混合ガベージ・コレクションの実行に切り替わります。混合ガベージ・コレクションでは、G1 GCは、収集されるEdenリージョンとSurvivorリージョンのセットに古いリージョンの一部をオプションで追加します。追加される古いリージョンの正確な数は、いくつかのフラグで制御されます(「推奨事項」の「混合ガベージ・コレクタの調整」を参照)。G1 GCが(混合ガベージ・コレクションを複数回実行して)十分な数の古いリージョンを収集すると、G1は次のマーキング・サイクルが完了するまで、若いガベージ・コレクションの実行に戻ります。
マーキング・サイクルには次のフェーズがあります。
初期マーキング・フェーズ: G1 GCはこのフェーズ中にルートをマークします。このフェーズは通常の(STW型)若いガベージ・コレクションに乗じて実行されます。
ルート・リージョン・スキャン・フェーズ: G1 GCは、初期マーキング・フェーズでマークされたSurvivorリージョンをスキャンして古い世代への参照を検索し、参照オブジェクトをマークします。このフェーズはアプリケーションと並行実行され(STW型でない)、次のSTW型の若いガベージ・コレクションが開始される前に完了している必要があります。
コンカレント・マーキング・フェーズ: G1 GCはヒープ全体で到達可能な(ライブ)オブジェクトを検索します。このフェーズはアプリケーションと並行して行われ、STW型の若いガベージ・コレクションによって中断される可能性があります。
再マーク・フェーズ: このフェーズはSTWコレクションで、マーキング・サイクルの完了を促します。G1 GCはSATBバッファを排出し、未探索のライブ・オブジェクトをトレースして、参照処理を実行します。
クリーンアップ・フェーズ: この最終フェーズで、G1 GCはアカウンティングとRSetの除去を行うSTW操作を実行します。アカウンティングでは、G1 GCは完全に空き状態のリージョンと混合ガベージ・コレクションの候補を識別します。クリーンアップ・フェーズは、空のリージョンをリセットして空きリストに戻すときは部分的にコンカレントです。
G1 GCは適応型ガベージ・コレクタであり、デフォルト値を変更せずにそのまま使用して効果的に動作できます。表10-1「G1ガベージ・コレクタの重要なオプションのデフォルト値」に、Java HotSpot VMビルド24の重要なオプションとそのデフォルト値を一覧で示します。現在のアプリケーションのパフォーマンス要件に合せてG1 GCを適応およびチューニングするには、JVMコマンド行で表10-1「G1ガベージ・コレクタの重要なオプションとデフォルト値」のオプションを入力し、変更後の設定値を指定します。
表10-1 G1ガベージ・コレクタの重要なオプションのデフォルト値
オプションとデフォルト値 | オプション |
---|---|
|
G1リージョンのサイズを設定します。この値は2の累乗で、1MBから32MBの範囲で指定できます。最小Javaヒープ・サイズを基に、リージョンが約2048個になるようにします。 |
|
望ましい最大一時停止時間の目標値を設定します。デフォルト値は200ミリ秒です。指定された値はヒープ・サイズには適応されません。 |
|
若い世代の最小サイズとして使用するヒープの割合を設定します。デフォルト値は現在のJavaヒープの5%です。脚注1 これは試験的なフラグです。「試験的なVMフラグのロック解除方法」で例を参照してください。この設定は |
|
若い世代の最大サイズとして使用するヒープ・サイズの割合を設定します。デフォルト値は現在のJavaヒープの60%です。脚注1 これは試験的なフラグです。「試験的なVMフラグのロック解除方法」で例を参照してください。この設定は |
|
STWワーカー・スレッドの値を設定します。 論理プロセッサが9個以上ある場合は、nの値を論理プロセッサ数の約5/8に設定します。これはほとんどのケースで機能しますが、nの値が論理プロセッサ数の約5/16になるような大規模なSPARCは例外です。 |
|
パラレル・マーキング・スレッド数を設定します。 |
|
マーキング・サイクルを開始するJavaヒープ占有率のしきい値を設定します。デフォルトの占有率はJavaヒープ全体の45%です。 |
|
混合ガベージ・コレクション・サイクルに含める古い世代の占有率のしきい値を設定します。デフォルトの占有率は85%です。脚注1 これは試験的なフラグです。「試験的なVMフラグのロック解除方法」で例を参照してください。この設定は |
|
未使用にするヒープの許容割合を設定します。再生可能な割合がヒープの未使用率を下回ると、Java HotSpot VMは混合ガベージ・コレクション・サイクルを開始しません。デフォルトは5%です。脚注1 |
|
マーキング・サイクル後に古いリージョンのライブ・データ(最大で |
|
混合ガベージ・コレクション・サイクル時に収集する古い世代の数に上限を設定します。デフォルトはJavaヒープの10%です。脚注1 |
|
To領域のオーバーフローのリスクを緩和するため、空き状態を維持する予約メモリーの割合を設定します。デフォルトは10パーセントです。この割合を増減するときは、必ずJavaヒープの合計量を同量分調整してください。脚注1 |
脚注1この設定はJava HotSpot VMビルド23以前では使用できません。
試験的なフラグの値を変更するには、最初にロック解除する必要があります。これを行うには、コマンド行で試験的なフラグの前に-XX:+UnlockExperimentalVMOptions
を明示的に設定します。次に例を示します。
java -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=10 -XX:G1MaxNewSizePercent=75 G1test.jar
G1 GCを評価してチューニングするときは、常に次の推奨事項を考慮してください。
若い世代のサイズ: -Xmn
オプションやその他の関連オプション(-XX:NewRatio
など)を使用して、若い世代のサイズを明示的に設定しないでください。若い世代のサイズを固定すると、指定した一時停止時間目標がオーバーライドされます。
一時停止時間目標: ガベージ・コレクションの評価やチューニングを行うときは、遅延時間とスループットのトレードオフが常に生じます。G1 GCは、均一な一時停止を伴うインクリメンタル・ガベージ・コレクタですが、アプリケーション・スレッドのオーバーヘッドも大きくなります。G1 GCのスループット目標は、アプリケーション時間が90%、ガベージ・コレクション時間が10%です。これをJava HotSpot VMのパラレル・コレクタと比較してみましょう。パラレル・コレクタのスループット目標は、アプリケーション時間が99%、ガベージ・コレクション時間が1%です。したがって、G1 GCのスループットを評価するときは、一時停止時間目標を緩くしてください。あまり積極的な目標を設定すると、ガベージ・コレクションのオーバーヘッドが増加しても構わないという意味に解釈され、スループットに直接影響します。G1 GCの遅延時間を評価するときは、望ましい(ソフト)リアルタイム目標を設定すると、G1 GCはその目標を満たそうと努力します。その影響として、スループットが犠牲になります。詳細は、「ガベージファースト・ガベージ・コレクタ」の「一時停止時間目標」を参照してください。
混合ガベージ・コレクションの調整: 混合ガベージ・コレクションのチューニングを行うときは、次のオプションを試してください。これらのオプションの詳細は、「重要なデフォルト」を参照してください。
-XX:InitiatingHeapOccupancyPercent
: マーキングのしきい値を変更する場合に使用します。
-XX:G1MixedGCLiveThresholdPercent
および-XX:G1HeapWastePercent
: 混合ガベージ・コレクションの各種判定を変更する場合に使用します。
-XX:G1MixedGCCountTarget
および-XX:G1OldCSetRegionThresholdPercent
: 古いリージョンのCSetを調整する場合に使用します。
「to-space overflow」または「to-space exhausted」メッセージがログに表示されている場合、G1 GCではSurvivorオブジェクトまたは昇格されたオブジェクト(あるいはその両方)用のメモリーが不足しています。Javaヒープはすでに最大値に達しているので拡張できません。メッセージの例:
924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space exhausted), 0.1957310 secs]
924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space overflow), 0.1957310 secs]
この問題を改善するには、次のように調整してみてしてください。
-XX:G1ReservePercent
オプションの値を(ヒープの合計サイズも相応に)増やして、To領域(to-space)用の予約メモリーの容量を増やします。
-XX:InitiatingHeapOccupancyPercent.
の値を減らして、マーキング・サイクルの開始を早めます。
-XX:ConcGCThreads
オプションの値を増やして、パラレル・マーキング・スレッドの数を増やします。
これらのオプションの詳細は、「重要なデフォルト」を参照してください。
G1 GCでは、リージョン・サイズの半分を超えるようなオブジェクトはすべて大型(humongous)オブジェクトとみなされます。このようなオブジェクトは、古い世代のHumongousリージョンに直接割り当てられます。これらのHumongousリージョンは、連続したリージョンのセットです。StartsHumongous
では連続セットの開始をマークし、ContinuesHumongous
はそのセットの継続をマークします。
Humongousリージョンの割当てが行われる前に、マーキングのしきい値がチェックされ、必要に応じてコンカレント・サイクルが開始されます。
寿命を終えた大型オブジェクトは、マーキング・サイクルの最後のクリーンアップ・フェーズ中と、フル・ガベージ・コレクション・サイクル時に解放されます。
コピー処理のオーバーヘッドを減らすため、大型オブジェクトは退避の一時停止には含まれません。フル・ガベージ・コレクション・サイクルでは、大型オブジェクトをその場で圧縮します。
StartsHumongous
リージョンとContinuesHumongous
リージョンの個々のセットには、1つの大型オブジェクトのみが含まれるので、大型オブジェクトの終わりとオブジェクトが割り当てられた最後のリージョンの終端との間にある領域は未使用な状態です。オブジェクトのサイズがヒープ・リージョンのサイズの倍数をわずかに上回るだけの場合は、この未使用領域によってヒープが断片化される可能性があります。
Humongousの割当てが原因でコンカレント・サイクルが相次いで開始され、このような割当てによって古い世代が断片化されている場合は、-XX:G1HeapRegionSize
の値を増やし、以前の大型オブジェクトが大型として扱われなくなり、通常の割当て方法に従って処理されるようにします。