G1GC でヒープ開放 JEP 346 Promptly Return Unused Committed Memory from G1

blog1.mammb.com


はじめに

G1GC は、full GC か concurrent cycle で Java Heep を解放しますが、G1GC は full GC を回避するように試み、concurrent cycle も ヒープ占有率とアロケーションアクティビティを基にトリガされるため、多くのケースで Java Heep は解放されません。

メモリリソースの一部しか利用していない状況でも、G1 は Heep を保持し続けるため、リソース使用分に応じて課金されるコンテナ環境などでは、この挙動はデメリットになります。 これが改善できれば、Tomcat サーバの実際の使用を基にしたプロトタイプテストにおいて、夜間のアイドル時間帯で、コミット済みメモリの 85% を減少可能としています。

JDK 12 では、上記改善のため以下の3つのJVMオプションが追加され、G1 GC からのメモリ返却が制御可能になりました。

  • G1PeriodicGCInterval
  • G1PeriodicGCSystemLoadThreshold
  • G1PeriodicGCInvokesConcurrent


G1PeriodicGCInterval

G1 が定期的なガベージ・コレクションをトリガーする必要があるかどうかを確認する間隔(ミリ秒)を指定します。 デフォルトではゼロに設定されており、これは無効を意味します。

-XX:G1PeriodicGCInterval=60000 // 60秒間隔

G1PeriodicGCIntervalミリ秒以上が、以前のガベージコレクション休止から経過しており、この時点で進行中の同時サイクルがない場合、アプリケーションは非アクティブとみなされ、G1 は定期的なガベージ・コレクションをトリガーします。


G1PeriodicGCSystemLoadThreshold

G1PeriodicGCInterval によるガベージ・コレクションを、システム負荷が高い場合に実行させないようにします。

現在のシステム負荷(ホストの getloadavg() コールで返される1分間の平均システム負荷値)がこの値よりも高いと、定期的なガベージ・コレクションはキャンセルされます。

デフォルトはゼロで、この条件は無視されます。

-XX:G1PeriodicGCSystemLoadThreshold=0.0


G1PeriodicGCInvokesConcurrent

定期的なガベージ・コレクションのタイプ(コンカレントかそうではないか)を設定します。

設定されている場合は、定期的なガベージ・コレクションでコンカレント・マーキングがトリガーされるか、既存のコレクション・サイクルが継続されます。

設定されていない場合はフルGCがトリガーされます。

-XX:+G1PeriodicGCInvokesConcurrent


まとめ

JDK 12 から、G1 GC でヒープを OS に返却するオプションが追加されました。

デフォルトはOFFになっているため、G1PeriodicGCInterval を設定すればヒープが定期的に開放されるようになります。挙動を細かく制御したい場合は、G1PeriodicGCSystemLoadThresholdG1PeriodicGCInvokesConcurrent が用意されています。

アクティブな時間帯とアイドルな時間帯が分かれるサーバアプリケーションやクライアントアプリケーションなどにおいては、G1PeriodicGCInterval を設定しておくのが良いでしょう。