読者です 読者をやめる 読者になる 読者になる

sugarlife's blog

Javaとか、http://twitter.com/sugarlife

CMS GC おさらい

この記事は Java Advent Calendar 2014 の一日目の記事です。

先日の JJUG CCC 2014 FallCMS GC について話してきました。
結構遅めの時間帯にも関わらず、200人規模の部屋がいっぱいに埋まるぐらいの盛況振りで、みなさんGCにお困りなんだなあと実感しました。スライドは以下に公開しています。CMS GC の挙動から GC ログの読み方、どういうケースが厄介なのかを紹介しているので是非ご覧ください!

嬉しいことにセッションの反応は良かったのですが、「遅めの時間帯で頭も疲れてるとガチ話辛い」という声もあったので、今回は CMS GC について比較的重要な点についてだけ簡単におさらいしたいと思います。

オプションについて

@nekop さんの「Java 7 CMS GCの基本的な情報の整理 - nekop's blog」を読めば OK 。

上の記事から追記するとしたら

  • -Xmx と -Xms は同じ値にしたほうが、拡張/シュリンク時に Major GC などの負荷が発生しないのでお勧め。
    • 積極的にシュリンクさせたいなら MaxHeapFreeRatio も変更しないと多くの場合では期待している動作にならないので注意。
    • ちなみに JDK8 以前はこのバグで実はシュリンクできていなかったケースとかもある。
  • -XX:+CMSClassUnloadingEnabled は JDK8 でデフォルト True なので、もう True で良いと思う。
    • JDK 8 で False にしてると、(Metaspaceを使いまくるアプリなら) Metaspace が際限なく増えて最終的に JVM 落ちるんじゃないかな。
    • 有効にすることで増える Remark フェーズの GC ポーズの秒数は下のスライドのログ見れば解る。

他、CMS GC の発生条件のチューニングとして、以下のスライドで CMSInitiatingOccupancyFraction と UseCMSInitiatingOccupancyOnly を紹介しました。

UseCMSInitatingOccupancyOnly を使わずに、チューニングすることも可能ですが、自分が知っている限りでこれが無効の場合の CMS GC 開始条件は、

  • CMS 実行間隔の統計的に、今実行しないとヒープが不足すると判断された場合
  • 最初の CMS 実行時に、ヒープ使用率が CMSBootstrapOccupancy で指定した値を超えていた場合
  • ヒープ領域拡張した結果、GC を行わなくてもメモリ確保に成功した場合
  • 断片化によってまとまったメモリ空間の確保に失敗すると判断された場合

と、これ以外(インクリメンタル CMS やパーマネント領域関係とか)にもあるのでここら辺を一つ一つやるよりは UseCMSInitiatingOccupancyOnly で調整したほうが楽です。

GC ログの読み方について

GC ログの読み方はスライドの P.37 以降に一つ一つ書いているのでそちらで!
特に重要そうな点は以下の通りです。

  • CMS GC と Full GC は別物
    • CMS GC は Initial mark ([1 CMS-initial-mark) と Remark ([1 CMS-remark) フェーズでアプリケーションが止まる。それ以外の時間はアプリは動く。
    • Full GC は Mark Sweep Compaction アルゴリズムであり、実行時はアプリケーションが止まる。
      • promotion failed か concurrent mode failure が出力された時にFullGCが実行される。[Full GC が出力されない場合もある。
      • Full GC対策はスライド参照(P.71から)。
  • CMS: abort preclean due to time」はエラーじゃない。
  • GC locker: Trying a full collection because scavenge failed」が出たら CMS GC は諦めて コンパクションのある GC を使うのがお勧め。

おわりに

CMS GC ではパフォーマンス的にどうにもならない時もあります。どうにもならないことが掴めたら G1GC や Parallel GC、Azul Zingを使うことを検討しましょう。

これ以外にも OpenJDK にはまた新しい GC として G1GC リプレース型の Pauseless GC である Shenandoah がやってきます。JavaOne2014 でも発表していましたが、資料はこっちの方(「Shenandoah An ultra-low pause time Garbage Collector for OpenJDK」)が解りやすいかな。Remembered set絡みの処理が早くなるアイデアで、G1GC より停止時間が優れてる感じっぽいと受け取りましたが、出てくるのはしばらく後ですね。こんな感じで GC との付き合いはしばらく続きそうです。