JDK 26 G1/Parallel/Serial GC changes

原文はこちら。
The original article was written by Thomas Schatzl (OpenJDK developer, Oracle).
https://tschatzl.github.io/2026/02/26/jdk26-g1-serial-parallel-gc-changes.html

OpenJDKプロジェクトは、数日中にJDK 26をリリースする予定です。これは、Hotspot VMのstop-the-world型ガベージコレクタにおける注目すべき変更点に関する情報を追加する良い機会です。

JDK 26のGCサブコンポーネントに関して解決またはクローズされた変更点の完全なリストはこちらにあるとおりで、合計で約380件の変更が含まれています。

前回のリリースと比較して、JDK 26では約2倍の数の課題がクローズされました。簡単な分析によると、変更内容の構成が異なっていることがわかります。つまり、少数の大規模な変更ではなく、エンドユーザーに目に見えるものや単なるコード品質の改善といった、多くの小さな変更があったということです。大規模な変更のほとんどは早期に統合されたため、開発時間の大部分は以前のリリース期間に費やされました。さらに、GCコンポーネントへの新規貢献者数名が、大きな影響を与えました。

まずは、JDK 26における「stop-the-world」ガベージコレクタ別に分類した、私見で特筆すべき変更点の概要から見ていきましょう。

All Collectors

本リリースでは、すべてのガベージコレクタ(非stop-the-world型コレクタを含む)に影響を与える大幅な変更が行われました。

GCにおけるCPU使用率の改善

GCにおけるCPU使用率が大幅に改善されました。VMは現在、GCポーズ時間に加え、並行処理(例:並行マーキング)や文字列の重複排除などの関連タスクに費やされたCPU時間を含め、より包括的な方法でGCのCPU使用率を追跡するようになりました。

以前のリリースでは、この情報は断片的であったり手動での集計が必要であったりしたため、ユーザーが確実に取得することは困難、あるいは不可能でした。

現在では、その情報を取得する複数の方法があります。その一つは、cpu=info ロギングを有効にすることです。これにより、VM終了時に以下のような出力が表示されます。

[info ][cpu] === CPU time Statistics =========================================
[info ][cpu]                                                          CPUs
[info ][cpu]                                              s       %  utilized
[info ][cpu]    Process
[info ][cpu]      Total                            443.4045  100.00       9.0
[info ][cpu]      Garbage Collection               365.2198   82.37       7.4
[info ][cpu]        GC Threads                     365.1982   82.36       7.4
[info ][cpu]        VM Thread                        0.0216    0.00       0.0
[info ][cpu] =================================================================

JEP 516関連の改善

JEP 516(Ahead-of-Time Object Caching with Any GC)では、すべての Hotspot GCで適切に動作することを明確な目標として、Ahead-of-Time (AOT) リンク済みおよびロード済みオブジェクトを読み込むための新しいメカニズムが導入されています。その理由は、Project Leyden をGCアルゴリズムに依存せずにサポートするためです。

JEP 516: Ahead-of-Time Object Caching with Any GC
https://openjdk.org/jeps/516
JEP 483: Ahead-of-Time Class Loading & Linking
https://openjdk.org/jeps/483
Project Leyden
https://openjdk.org/projects/leyden/

以前の AOT キャッシュのディスク形式は、GC アルゴリズムや VM オプションに依存していたため、特に ZGC への拡張が困難でした。新しいフォーマットは、GCに依存せず、VMオプションからも独立しています。

ただ欠点として、新しいアルゴリズムでは起動時により多くの処理が必要です。JEP 516の実装では、起動中にアプリケーションと並行してオブジェクトを初期化することで、この起動時の影響を軽減しています。

新しいフォーマットを有効にするには、新しい-XX:+AOTStreamableObjectsコマンドラインオプションを使用してください。

シャットダウンプロセスの堅牢性向上

シャットダウンプロセスの堅牢性が向上しました。JDK 26以前では、ガベージコレクションサブシステムがすでにシャットダウンした後にJVMTIエージェントがメモリを割り当てる可能性があり、これによりハング、メモリ不足エラー、またはクラッシュといった予期しない動作が発生する恐れがありました。

関連するIssueには、JDK-8367902およびJDK-8366865があります。

[JDK-8367902] Allocation after Universe::before_exit() in the VM shutdown sequence
https://bugs.openjdk.org/browse/JDK-8367902
[JDK-8366865] Allocation GC Pauses Triggered after JVM has started shutdown
https://bugs.openjdk.org/browse/JDK-8366865

コマンドラインオプション

多数のコマンドラインオプションで、デフォルト値が変更されたり、廃止予定として非推奨になったりしています。

-XX:InitialRAMPercentageは、インストールされたメモリの割合に基づいて起動時に確保されるJavaヒープの量を決定するオプションですが、デフォルト値が0に変更されました。つまり、インストールされた総メモリ量は、初期のJavaヒープサイズに影響しなくなりました。

[JDK-8371987] Remove the default value of InitialRAMPercentage
https://bugs.openjdk.org/browse/JDK-8371987

実際には、起動時にVMによって確保されるメモリ量(起動時間に影響します)は、起動時にマシンの搭載RAMの一定割合をJavaヒープとして恣意的に初期化するのではなく、他のメカニズム(-XX:MinHeapSize/-Xms/-XX:InitialHeapSizeなど)によって導出された最小ヒープサイズに従うようになりました。

この変更に関するCSRには、変更の理由がさらに詳しく説明されています。

[JDK-8371987] Remove the default value of InitialRAMPercentage
https://bugs.openjdk.org/browse/JDK-8371987

主に「長時間実行されるメモリ集約型のベンチマークシナリオ」向けに一連の最適化を集約する -XX:AggressiveHeap も非推奨となりました。汎用的な名称であること、SPECjbb に重点が置かれていること、また、現在では非常に多様化したこれらのアプリケーション環境において同様のチューニングセットを見つけることが複雑であるといった複数の理由から、近い将来に削除されることになりました。CSR には、その効果を手動で再現したい場合に有効にするオプションが記載されています。

[JDK-8370814] Deprecate AggressiveHeap
https://bugs.openjdk.org/browse/JDK-8370814

あまり知られておらず、通常は内部テストでのみ使用されていたオプションのうち、次期リリースで削除される予定のものは、-XX:MaxRAM (JDK-8369346)、-XX:AlwaysActAsServerClassMachine、および-XX:AlwaysActAsServerClassMachine (JDK-8370844) です。これらの効果は同様に、他のオプションで置き換えることができます。

[JDK-8369346] Remove default value of and deprecate the MaxRAM flag
https://bugs.openjdk.org/browse/JDK-8369346
[JDK-8370844] Deprecate AlwaysActAsServerClassMachine and NeverActAsServerClassMachine
https://bugs.openjdk.org/browse/JDK-8370844

新たなJFRイベント

最後に、文字列の重複排除の結果を詳細に記録する新しい JFR イベントが追加されました(JDK-8360540)。これにより、ログの解釈に依存する必要性が軽減されます。

[JDK-8360540] nmethod entry barriers of new nmethods should be disarmed
https://bugs.openjdk.org/browse/JDK-8360540

Parallel GC

JDK 26では、Parallel GCに関する変更は比較的少なかったと言えます。エンドユーザーにとって最も重要なのは、おそらくいくつかのVMオプションの非推奨および廃止でしょう。

-XX:ParallelRefProcEnabledオプションの非推奨、など

-XX:ParallelRefProcEnabledオプションの非推奨(JDK-8359924)は、エンドユーザーに影響を与える可能性が最も高い変更です。このオプションは、java.lang.ref.Referenceの処理フェーズの並列化を制御します。このオプションは長期間にわたりデフォルトで有効化されており、問題も発生していなかったため、維持する理由はありませんでした。特に、このフェーズの並列度を下げる必要がある場合は、-XX:ReferencesPerThreadを使用することで、スレッドごとの処理量を変更し、同様の効果を得ることができます。

[JDK-8359924] Deprecate and obsolete ParallelRefProcEnabled
https://bugs.openjdk.org/browse/JDK-8359924

G1もこのオプションを使用していたため、今回の変更による影響はG1も同様です。

さらに、あまり知られていない Parallel GC 専用のオプションがいくつか、非推奨、廃止、または削除されました。-XX:PSChunkLargeArrays (JDK-8360628)、 -XX:HeapMaximumCompactionInterval (JDK-8366882)、およびデバッグビルド限定のGCExpandToAllocateDelayMillis (JDK-8363229)などです。

[JDK-8360628] Parallel: Deprecate and obsolete PSChunkLargeArrays
https://bugs.openjdk.org/browse/JDK-8360628
[JDK-8366882] Parallel: Obsolete HeapMaximumCompactionInterval
https://bugs.openjdk.org/browse/JDK-8366882
[JDK-8363229] Parallel: Remove develop flag GCExpandToAllocateDelayMillis
https://bugs.openjdk.org/browse/JDK-8363229

Serial GC

内部的にはいくつかの重要な変更(例:アドレス空間におけるEden領域とSurvivor領域の入れ替え(JDK-8368740))やリファクタリングが行われましたが、このリリースではユーザーに目に見える大きな変更はありませんでした。

[JDK-8368740] Serial: Swap eden and survivor spaces position in young generation
https://bugs.openjdk.org/browse/JDK-8368740

G1 GC

G1は、汎用的な変更に加え、stop-the-world型コレクタの中で最も多くの変更を受けました。

JEP 522に伴う変更

G1 にとって、ここしばらくの間で断然最大かつおそらく最も影響力の大きい単一の変更点は、JEP 522です。

JEP 522: G1 GC: Improve Throughput by Reducing Synchronization
https://openjdk.org/jeps/522

以前の投稿でこの変更について詳しく説明しています。

New Write Barriers for G1
https://tschatzl.github.io/2025/02/21/new-write-barriers.html
https://logico-jp.dev/2025/03/22/new-write-barriers-for-g1/

要約すると、G1 におけるGCとアプリケーション間のメモリ同期は、Serial GC やParallel GC とほぼ同等のレベルまで削減されました(ここには改善の余地があります)。これによりスループットが向上し、G1はParallel GCとの競争力を高めました。その一方で、G1を堅実なデフォルトの選択肢としている他のアルゴリズム特性(低くて予測可能な停止時間、スケーラビリティ、妥当なネイティブメモリ使用量)に対する妥協は最小限に抑えられています。G1は、長いfull GCを発生させることなく、Parallel GCに匹敵するほぼ素のスループットを達成できるようになったはずです。

この変更は、G1を真の唯一のデフォルトGCにするための重要なマイルストーンですが、さらなる作業が必要です。

JEP 523: Make G1 the Default Garbage Collector in All Environments
https://openjdk.org/jeps/523

自動ヒープサイズ調整

今回のリリースサイクルを通じて、私たちの注力の大部分は、G1向けの自動ヒープサイズ調整の作業に注がれてきました。

[JDK-8359211] Automatic Heap Sizing for G1 – Java Bug System
https://bugs.openjdk.org/browse/JDK-8359211

この取り組みの目標は、G1が環境条件に基づいてJavaヒープのサイズを決定できるようにすることです。つまり、空きメモリが豊富な場合は、パフォーマンス向上に役立つのであれば利用可能なリソースをより多く使用し、一方で、近隣のプロセスやその他のシステム状況によって利用可能なメモリが減少した場合は、VMの総メモリ使用量を縮小するようにします。その結果、将来的には多くの導入環境において、最大ヒープサイズ(-Xmx/-XX:MaxHeapSize)の手動調整がほとんど不要になるはずです。

この目標に向けた取り組みには、CPU使用率に基づいてJavaヒープメモリの使用状況をより頻繁に再評価すること(JDK-8238687)が含まれます。これは、GC CPU使用率のより適切な監視(JDK-8359348)とも関連しており、GC CPU使用率の計算において、並行処理も考慮されるようになりました。

[JDK-8238687] Investigate memory uncommit during young collections in G1
https://bugs.openjdk.org/browse/JDK-8238687
[JDK-8359348] G1: Improve cpu usage measurements for heap sizing
https://bugs.openjdk.org/browse/JDK-8359348

これは、長らく待たれていたデフォルトのG1 GC CPU使用率目標値の引き下げ(JDK-8247843)とも整合しています。この変更により、デフォルト値は8%から4%に引き下げられました。

[JDK-8247843] Reconsider G1 default GCTimeRatio value
https://bugs.openjdk.org/browse/JDK-8247843

元の値はG1の初期リリース時に設定されたものですが、長年にわたりG1は大幅に高速化され、より多様なワークロードにおいて一貫したパフォーマンスを発揮するようになりました。また、以前よりも狭いヒープ領域や低いGC CPU使用率でも、同等のパフォーマンスを維持できることが多くなっています。

UseGCOverheadLimitのサポート

最も頻繁に要望されていたParallel GCの機能の一つが、-XX:UseGCOverheadLimitのサポートです (JDK-8212084)。

[JDK-8212084] G1: Implement UseGCOverheadLimit
https://bugs.openjdk.org/browse/JDK-8212084

このオプションが有効になっている場合(デフォルトで有効)、GCのCPU使用率がしきい値(-XX:GCTimeLimit、デフォルト98%)を上回り、かつJavaヒープの空き領域が別のしきい値(-XX:GCHeapFreeLimit、デフォルト2%)を下回った状態が長時間続くと、VMはOut-Of-Memory例外をスローします。これは、設定が著しく不適切なVMが、アプリケーションが実際に処理を進められないまま、ほぼすべての時間をGCに費やしてしまう状況を回避することを目的としています。

gc=infoレベル以下のログメッセージには、トリガー条件がどのように満たされたかについての追加情報が含まれています。

その他のパフォーマンス改善

いつものように、一般的なパフォーマンスの改善もいくつか行われました。並列化の取り組み(例:JDK-8363932)や、イアガー・リクレイム(eager reclaim)メカニズムの改善などです。以下のドキュメントで説明されている動作が、すべての種類の巨大オブジェクト(JDK-8048180)に適用されるようになりました。

Humongous Objects – Garbage-First (G1) Garbage Collector – HotSpot Virtual Machine Garbage Collection Tuning Guide
https://docs.oracle.com/en/java/javase/25/gctuning/garbage-first-g1-garbage-collector1.html#GUID-D74F3CC7-CC9F-45B5-B03D-510AEEAC2DAC

CRには、ヘッドルームが制限されているシナリオにおいて、これが予期せぬ頻度や長時間のコレクションをどのように削減できるかを示すパフォーマンスグラフが含まれています。

[JDK-8363932] G1: Better distribute KlassCleaningTask – Java Bug System
https://bugs.openjdk.org/browse/JDK-8363932
[JDK-8048180] G1: Eager reclaim of humongous objects with references – Java Bug System
https://bugs.openjdk.org/browse/JDK-8048180

最後に、起動時の改善(例:JDK-8371019)は、Project Leydenの取り組みを支援します。

[JDK-8371019] G1: Support heap expansion during startup – Java Bug System
https://bugs.openjdk.org/browse/JDK-8371019
Project Leyden
https://openjdk.org/projects/leyden/

What’s next

引き続き、自動ヒープサイズ調整に注力し、メモリ管理の様々な側面に対する制御を改善することで、G1(および一般的なstop-the-world型コレクタ全般)が、外部環境やユーザーの意図に対してより賢く対応できるようにします。並行して、ガベージコレクション分野におけるJEP 401に関する作業も進行中です。

JEP 401: Value Classes and Objects (Preview)
https://openjdk.org/jeps/401

Thanks go to…

いつものように、今回の強力なJDKリリースの実現に貢献してくださったすべての方々に感謝申し上げます。私にとって、今回のリリースは、この概要を書き始めた当初予想していたよりも、規模が大きく、広範な影響力を持つものとなりました。次回の(さらに大規模な)リリースでお会いできるのを楽しみにしています。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください