Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【Java】G1GC

Javaのガーベジコレクタ

【Java】JVMのヒープメモリ管理の記事では、JVMがどのようなガーベジコレクタアルゴリズムを搭載しているかについて調査・紹介しました。今回はJavaGCアルゴリズムの詳細実装であるG1GC(Garbage First Garbage Collector)について調べてみました。

G1GCとは

G1GCはJava7より実装され、Java9では標準実装となったCGアルゴリズムです。 G1GCの特徴として

  • 大容量メモリ搭載マシンを対象とする
  • マルチプロセッサマシンを対象とする
  • ユーザが指定する、GCによる一時停止目標時間を高い確率で満たすことができる
  • ヒープ圧縮効率が従来のGCCMS)よりも比較的良い
  • グローバルマーキング(後述)等のGC処理はアプリケーションスレッドと並行して動作する

点が挙げられます。

G1GCのアルゴリズム

G1GCは、ヒープ領域を「リージョン」と呼ばれる均等領域に分割します。G1GCアルゴリズムは各リージョンに対して、使われていないオブジェクトに対して印をつけていきます(グローバル・マーキング・フェーズと呼ばれます)。印を付け終わったあと、印のついていないオブジェクト、すなわちガーベジでいっぱいになったリージョンが見つかった場合、G1GCは印の付いたオブジェクトだけを他の単一のリージョンにコピーし、コピー元のリージョンをクリーンします(コピーGC)。ガーベジでいっぱいとなったリージョンを優先的に開放するところが、ガーベジ・ファーストと呼ばれる所以だそうです。

リージョン間のコピーGCによって、メモリーの解放処理だけでなく圧縮にも成功しています。これは、同じくJavaのガーベジコレクタアルゴリズムであるCMS(Concullent Mark&Sweep)が圧縮処理を行わないことに対する大きなアドバンテージです。

世代別GC

【Java】JVMのヒープメモリ管理の記事では、世代別GCについて扱いました。実は、先程説明したG1GCのアルゴリズムには、世代別GCの概念が導入されています。G1GCではヒープ領域をリージョンという単位に分割すると述べましたが、このリージョンは「New領域」「Tenured領域」の二種類に分かれます。またNew領域は「Eden領域」と「Serviver領域」に分割されます。

新しく生成されたオブジェクトはEden領域に格納されていきます。Eden領域には頻繁にマーク&コピーGCが実施され、生き残ったオブジェクトは一部のServiver領域へとコピーされます(Eden領域は開放されます)。Serviver領域に対してもEdenと同じタイミングでGCが行われ、生き残ったオブジェクトは別のServiver領域へコピーされます。数回生き残ったオブジェクトはTenured領域へとコピーされ、頻繁なGCの対象とならなくなります。

f:id:rennnosukesann:20180331131333p:plain

ガベージファースト・ガベージ・コレクタ より引用 )

上図では、New領域が単色水色、Tenured領域がグラデーションの水色で示されています(なぜこの配色なのかは謎です。。)。矩形内の「S」はSuvivor領域であることを示し、赤いアイコンはGC対象領域であることを示しており、全てのNew領域と、一部のTenured領域がまさにGCされようとしています。このように毎回ではないものの、場合によってTenured領域を含むGCが走ることがあります。New領域に対するGCをYongGC、New領域と一部のTenured領域に対するGCをMixGC、JVMの対象とする、ヒープ全体へのGCをFullGCと言います。

なお、矩形内に「H」と書かれた領域はHumongous領域と呼び、大きいサイズのオブジェクトを格納するための領域です。この領域を解放するためには、FullGCを行うしかありません。

一時停止予測モデル

G1GCでは、ユーザが指定したGCによるアプリケーションの一時停止時間目標(GCによってどれくらいアプリケーションを止めてもよいか)を満たすべく、一時停止予測モデルを採用しその予測に基づいてリージョン数を調整しているそうです。

予測モデルをどのような仕組みで生成しているのかは不明ですが、モデルから将来の大まかな停止時間を導出し、ユーザが指定した停止時間目標内に収まるようリージョン数を増減させるものと思われます。なおこのユーザの目標停止時間は、JVMのフラグMaxGCPauseMillisで指定できます。

G1GCの推奨環境

ガーベジコレクションの対象となるアプリケーションが以下の条件を備えている場合、G1GCを採用するメリットが有ると公式では述べています。

  • Javaのヒープデータのうち、50%が非参照オブジェクトで占領される。

  • オブジェクトの割当率・昇格率が大きく変化する。

  • ガーベジコレクションによるアプリケーションの停止時間が望ましくない(0.5~1秒を超える)。

まとめ

G1GCでも世代別GCの概念を導入し、Mark&SweepとコピーGCによってメモリの開放と圧縮を効率的に行っていることがわかりました。次回はCMSについても詳しく調べてみようと思います。

参考文献

ガベージファースト・ガベージ・コレクタ