Changes to Garbage Collection in Java 12

このエントリは以下のエントリをベースにしています。
This entry is based on the one written by Bethan Palmer (Product Manager at IDRsolutions).
https://blog.idrsolutions.com/2019/03/changes-to-garbage-collection-in-java-12/

Java 12がまもなくリリースされます。Java 12はLTSリリースではありませんが、GCに対する機能追加が入っています。

1. Shenendoah: A new Garbage Collector

Java 12のデフォルトGCはG1のままですが、Shenendoahと呼ばれる新たな実験的GCが登場します。

ShenendoahはconcurrentかつparallelなオープンソースGarbage Collectorで、優れたレスポンスと短く信頼性のある休止時間を提供することを目的として開発されました。スループットとメモリ使用量よりもレスポンスを優先するため、そのトレードオフとして他のアルゴリズムよりも多くのメモリ領域が必要です。そのため、すべてのシナリオに最適となるようには設計されてはいませんが、より多くのメモリとCPUを搭載した最新のマシンを利用し、レスポンスを重視するGCが必要な場合は、これは興味深い選択肢たり得るでしょう。

How does it compare to other GCs?

Java 8でのデフォルトGCは高スループットを優先したParallel GCでした。GCでは複数のスレッドを使用していましたが、その間他のすべてのアプリケーションスレッドを停止していました(ポーズ時間が長くなる、”stop the world”として知られるアプローチ)。

Java 9以降、Garbage First (G1) がデフォルトGCになりました。Parallel GCとは異なり、Full GC時には全スレッド停止はありませんが、 ‘stop the world’ は発生します。G1GCのアルゴリズムはより短いポーズ時間を提供するものです。詳細は以下のURLなどをご覧ください。

Java Platform, Standard Edition — HotSpot Virtual Machine Garbage Collection Tuning Guide, Release 11
Garbage-First Garbage Collector
https://docs.oracle.com/en/java/javase/11/gctuning/garbage-first-garbage-collector.html (English)
https://docs.oracle.com/javase/jp/11/gctuning/garbage-first-garbage-collector.html (日本語)

Garbage-First Garbage Collector Tuning
https://docs.oracle.com/en/java/javase/11/gctuning/garbage-first-garbage-collector-tuning.html (English)
https://docs.oracle.com/javase/jp/11/gctuning/garbage-first-garbage-collector-tuning.html (日本語)

ShenendoahはG1と同様、アプリケーションスレッドと並行動作できますが、G1にはない並行退避 (concurrent evacuation) を使用します。これにより、Javaスレッドの実行中に、待避作業を実行してヒープを圧縮し、ポーズ時間をさらに短縮できます。ポーズ時間はヒープサイズとは無関係で、ヒープサイズの大小にかかわらず、ポーズ時間に違いはありません。

How does Shenendoah work?

通常、OpenJDKのオブジェクトヘッダには、(クラス名と、ロックや前方ポインタなどに使用されるmarkワードの)2ワードが割り当てられていますが、ShenendoahではIndirection Pointerと呼ばれる3個目のワードを追加しています。オブジェクトへのすべての参照はこのポインタを通る必要があります。これにより、すべての参照を更新せずにオブジェクトを移動できます。つまり、Javaスレッドが並行動作している間に生存オブジェクトをアップデートできる、ということです。この追加ワードはShenendoah GC利用時にのみ追加されます。

GCアルゴリズムには4フェーズあり、2個は短いstop the worldフェーズ、残りの2個はJavaスレッドと同時に実行できるより長いフェーズです。

  1. Initial Marking (短時間のStop the Worldフェーズ、ルートセットをトレースします)
  2. Concurrent Marking (長時間を要する同時実行フェーズ)
  3. Final Marking 短時間のStop the Worldフェーズ)
  4. Concurrent Compaction (長時間を要する同時実行フェーズ)

Shenendoah GCの詳細は以下の論文をご覧ください。

Shenandoah: An open-source concurrent compacting garbage collector for OpenJDK
https://www.researchgate.net/publication/306112816_Shenandoah_An_open-source_concurrent_compacting_garbage_collector_for_OpenJDK

How can I try Shenendoah?

Java 12をお使いであれば、以下のVMフラグを設定するとShenendoah GCを利用できます。-XX:+UnlockExperimentalVMOptionsが必要なのは、Shenendoah GCがまだ実験的機能だからです。

-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC

2. Enhancements to G1GC

Java 9以後のデフォルトGCであるG1GCにも、注目すべき2件の機能拡張が入っています。

G1は、GCで必要な作業量(コレクション・セット/Collection Set)を選択して起動してから、コレクションを開始します。コレクション開始後は、停止せずにすべてのライブオブジェクトを収集する必要があります。欠点は、コレクションセットが大きすぎると収集に時間がかかることです。

その欠点を改善すべく、JEP 344でアルゴリズムの機能拡張が入ります。

JEP 344: Abortable Mixed Collections for G1
https://openjdk.java.net/jeps/344

これは、誤った数のコレクションを選択し続け、時間がかかりすぎる場合、一方を実行必須、他方をオプション扱いに分割して、コレクションが目標ポーズ時間を過ぎていなければオプション部分を実行できるようにします。その後、いずれかのオプションフェーズ完了後にコレクションは停止できます。

もう一つの欠点は、Full GCもしくはコンカレントサイクル中のいずれかでのみ、G1はOSにヒープメモリを返します(とはいえ、G1は積極的にFull GCを避けるため、いずれの状況もそう頻繁には発生しません)。

JEP 346ではこの問題を解決するため、GCがアクティブでない期間にコンカレントサイクルを呼び出すようにします。

JEP 346: Promptly Return Unused Committed Memory from G1
https://openjdk.java.net/jeps/346

コンカレントサイクルが呼び出されると、自動的にヒープメモリをOSに返します。

というわけで、Java 12にはデフォルトGCであるG1に対して重要な改善が施されるとともに、Shenendoahという、新たなアルゴリズムの選択肢が追加されます。

Notice

2019/03/15時点では、以下にあるBugのため、JEP 346の機能は12.0.2以後で利用可能になるようです。

G1 crashes when issuing a periodic GC while the GCLocker is held
https://bugs.openjdk.java.net/browse/JDK-8218880

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中