JVMのヒープ領域とFull GC

(2016-11-14)

ヒープ領域

ヒープ領域というのはメモリ上の動的に確保する領域のこと。 JVMでは、ヒープ領域のNew領域とOld領域、非ヒープ領域のPermanent領域が存在する(した)。

Permanent領域

ロードしたクラスやメソッドが入る。 Java8版のHotspotVM(OracleのJVM)ではMetaspace領域となり、ネイティブメモリに乗るようになったらしい。

New領域

New領域の中はさらに分かれている。

  • Eden領域: オブジェクトが作られて最初に配置される。
  • To領域(Survivor領域1): Edenが一杯になると、EdenとFromから送られる。
  • From領域(Survivor領域0): Edenが一杯になると、Toから送られる。

Edenが一杯になったときに不要なオブジェクトは破棄、必要なものは領域を移動させるのがScavenge GC。 つまり、Edenが一杯になるたびにToに飛んだオブジェクトはFromと往復し続ける。 ただし、MaxTenuringThresholdの回数を超えるとOld領域に送られることになる。

Old領域

Old領域も一杯になったらどうしようもないのでFull GCが走る。 Full GCでは全ての領域のオブジェクトをチェックして不要なものを探す。 これに集中するので他のことはできなくなり、時間もかかる。 Full GCばかり起きていたらまともに動かないので、 Old領域にまで行かないようにオブジェクトの寿命を短くするか、 ヒープ領域の大きさ(-Xms, -Xmx)を変えたりしてなるべく起きないようにしたい。

どれくらいFull GCしているかどうか

-XloggcでGCのログが出せる。-XX:+UseGCLogFileRotationでローテーションしたりもできる。 あと手軽にjpsからのjstat -gc <pid>、あるいはグラフで可視化できるようなやつでヒープ領域の状態を確認する。 jstatの結果の意味はここに書いてある。 例えばFGCがフルGCイベントの数。

参考

JVMとGCのしくみ

Java8のHotSpotVMからPermanent領域が消えた理由とその影響 | ギークを目指して

Java開発の性能改善! その2 GCログの解析とHeepの設定