JDK 21 G1/Parallel GC changes

原文はこちら。
The original article was written by Thomas Schatzl (OpenJDK developer, Oracle).
https://tschatzl.github.io/2023/08/04/jdk21-g1-parallel-gc-changes.html

JDK 21 GAは順調です。OpenJDKのstop-the-world GCのこのリリースでの変更・アップデートも同様に。

JDK 21
https://openjdk.java.net/projects/jdk/21/

このリリースは、すべての OpenJDKディストリビューションではないにしても、ほとんどのOpenJDKディストリビューションでLTSに指定される予定です。前回のLTS (JDK 17) からのアップグレードで、GCの領域でもたらされるものの詳細は、JDK 18、JDK 19、JDK 20に関するの以前のブログエントリもご覧ください。

JDK 18 G1/Parallel/Serial GC changes
https://tschatzl.github.io/2022/03/14/jdk18-g1-parallel-gc-changes.html
https://logico-jp.io/2022/04/05/jdk-18-g1-parallel-serial-gc-changes/
JDK 19 G1/Parallel/Serial GC changes
https://tschatzl.github.io/2022/09/16/jdk19-g1-parallel-gc-changes.html
https://logico-jp.io/2022/09/23/jdk-19-g1-parallel-serial-gc-changes/
JDK 20 G1/Parallel/Serial GC changes
https://tschatzl.github.io/2023/03/14/jdk20-g1-parallel-gc-changes.html
https://logico-jp.io/2023/03/18/jdk-20-g1-parallel-serial-gc-changes/

このリリースに話を戻すと、stop-the-world GCを見る前に、おそらくこのリリースでGCに最もインパクトのある変更は、Generational ZGCの導入でしょう。

JEP 439: Generational ZGC
https://openjdk.org/jeps/439

これは、stop-the-world GCのようにYoungオブジェクトとOldオブジェクトの世代を維持するZGCの改良版であり、GCの作業を、ほとんどのgabageが通常作成される場所に注力させるというものです。これは、アプリケーションと歩調を合わせるために必要なJavaヒープとCPUオーバーヘッドが大幅に削減されます。Generational ZGCを有効にするには、-XX:+UseZGCフラグとともに、-XX:+ZGenerationalフラグを渡す必要があります。

これ以外の、HotSpot GCサブコンポーネント全体のJDK 21における完全な変更リストはこちらです。エントリ執筆時点で、全体で約250ほどの変更が解決済みもしくはクローズ済みです。これは以前のリリースに比べると少々多いですね。

以下は、Hotspotのstop-the-world GCならびにそれらに対するJDK 21での最も重要な変更点の一覧です。

Parallel GC

特筆すべき変更はありません。

Serial GC

特筆すべき変更はありません。

G1 GC

以下がJDK 21におけるG1のユーザー側の変更点です。

JDK-8191565

Full GCでのリージョンレベルの断片化によるOOMEの可能性を減らすため、G1はhumongous objectを移動するようになりました。JDK20までは、これまでhumongous object(大きなオブジェクト)を移動しませんでしたが、この制限をlast-ditch Full GCで解除しました。last-ditch Full GCは、通常のFull GCで現在の割り当てを満たすのに十分な(連続した)領域が得られなかった場合に発生します(JDK-8191565)。

[JDK-8191565] Last-ditch Full GC should also move humongous objects
https://bugs.openjdk.org/browse/JDK-8191565

この改良されたlast-ditch Full GCにより、以前発生していたいくつかのOut-of-Memoryの状況を回避できる可能性があります。

JDK-8302215

Full GCに関連するもう1つの改良(JDK-8302215)は、Full GC後にJavaヒープがよりコンパクトになるようにし、断片化を少し減らします。

[JDK-8302215] G1: Last-ditch Full GC should do serial compaction for tail regions in per thread compaction points.
https://bugs.openjdk.org/browse/JDK-8302215

Hot Card Cache

いわゆるHot Card Cacheは、JDK 20の並行改良の変更後に(少なくとも)影響がないことがわかったので、削除されました。このデータ構造には、アプリケーションが非常に頻繁に参照を変更する場所を収集することを意図していました。これらの場所は、常に同時並行的に修正するのではなく、次のガベージコレクションで一度だけ処理されるように、このHot Card Cacheに入れられた。この削除が興味深いものになる理由は、そのデータ構造が動作するために、Javaヒープ・サイズの0.2%というかなり大量のネイティブ・メモリーを使用していたからです。このネイティブメモリは、他の目的に使用できるようになりました。

対応するオプション-XX:+/-UseHotCardCacheで、Hot Card Cacheの利用を切り替えることはできなくなっています。

JDK-8302122 / JDK-8301116

何千ものスレッドを持つアプリケーションでは、以前のリリースでは、(スレッドごとの)TLABの撤収とセットアップのためにかなりのポーズ時間が費やされていました。この2つのフェーズはそれぞれJDK-8302122とJDK-8301116で並列化されました。

[JDK-8302122] Parallelize TLAB retirement in prologue in G1
https://bugs.openjdk.org/browse/JDK-8302122
[JDK-8301116] Parallelize TLAB resizing in G1
https://bugs.openjdk.org/browse/JDK-8301116

JDK-8297639

予防的GC機能は、JDK 20のエントリに記述した理由により、JDK-8297639で完全に削除されました。

[JDK-8297639] Remove preventive GCs in G1
https://bugs.openjdk.org/browse/JDK-8297639

https://tschatzl.github.io/2023/03/14/jdk20-g1-parallel-gc-changes.html#preventive
https://logico-jp.io/2023/03/18/jdk-20-g1-parallel-serial-gc-changes/#preventive

What’s next

JDK 22に向けた作業が始まっています。今回選ばれなかった機能については直ちに続行されます。以下は、すでに統合されている、あるいは現在開発中の興味深い変更点を書き出したものです。例によって、それらが次のリリースに間に合うという保証はありません。

JDK-8140326

old genを押しのける退避に失敗したリージョンに対するG1の回復力を向上させる変更は、しばらくの間レビューに出されていましたが、まもなくプッシュされようとしています (JDK-8140326, PR)。

[JDK-8140326] G1: Consider putting regions where evacuation failed into next collection set
https://bugs.openjdk.org/browse/JDK-8140326
8140326: G1: Consider putting regions where evacuation failed into next collection set by tschatzl
https://github.com/openjdk/jdk/pull/14220

この変更により、youngコレクションの特定の種類のみがold genリージョンでスペース回収できたいう、G1の過去の制約がなくなります。

Garbage-First (G1) Garbage Collector
https://docs.oracle.com/en/java/javase/20/gctuning/garbage-first-g1-garbage-collector1.html#GUID-F1BE86FA-3EDC-4D4F-BDB4-4B044AD83180
https://docs.oracle.com/javase/jp/20/gctuning/garbage-first-g1-garbage-collector1.html#GUID-F1BE86FA-3EDC-4D4F-BDB4-4B044AD83180

そのため、任意のyoungコレクションがも、通常の要件を満たせばold genリージョンから退避できます。

現在これが退避失敗後の速やかなスペース回収に役立っていますが、他の興味深いアイデアの中で、この変更により、固定されたリージョンが自由になった直後に、効率的でタイムリーな退避を可能にするために必要なインフラがもたらされます。

Garbage-First (G1) Garbage Collector
https://docs.oracle.com/en/java/javase/20/gctuning/garbage-first-g1-garbage-collector1.html#GUID-BE157AF6-29E7-461A-82CF-50C1978785DA
https://docs.oracle.com/javase/jp/20/gctuning/garbage-first-g1-garbage-collector1.html#GUID-BE157AF6-29E7-461A-82CF-50C1978785DA
JEP 423: Region Pinning for G1
https://openjdk.org/jeps/423

region pinningに関するPR

上記の変更により、リージョンの固定は1個のPR1だけで済むようになりました。

JDK-8308507

GCLockerが進行中のスレッドを浪費し、不要なメモリ不足例外を引き起こすという長年の問題に対する修正は、JDK-8308507で開発中であり、実際にレビュー目的で公開されている。

[JDK-8308507] G1: GClocker induced GCs can starve threads requiring memory leading to OOME
https://bugs.openjdk.org/browse/JDK-8308507
8308507: G1: GClocker induced GCs can starve threads requiring memory leading to OOME by walulyai
https://github.com/openjdk/jdk/pull/14077

今後もっと出てくるでしょう。

Thanks go to…

今回の素晴らしいJDKのリリースに貢献してくれた皆さん。次のリリースでお会いしましょう。

コメントを残す

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