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

nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

G1GCのつかいどころメモ

以下の環境とテストでCMSとG1GCを比較してみた。かなり急ぎでやったので間違っている可能性が多少ある。

  • 16 cores, 32GB mem
  • -Xms24g -Xmx24g
  • 8 instances Infinispan 6.0.3.Final DIST cache, put 4GB data (1KB entry * 2M, 2GB data with one backup copy, 2GB * 2 = 4GB)
  • CMS: -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=30
  • G1GC: -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:InitiatingHeapOccupancyPercent=30
$ java -XX:+UseG1GC -XX:+PrintFlagsFinal -version | grep -E 'MaxGCPauseMillis|G1HeapRegionSize|InitiatingHeapOccupancyPercent|ParallelGCThreads|ConcGCThreads'
    uintx ConcGCThreads                            := 3               {product}           
    uintx G1HeapRegionSize                          = 0               {product}           
    uintx InitiatingHeapOccupancyPercent            = 45              {product}           
    uintx MaxGCPauseMillis                          = 200             {product}           
    uintx ParallelGCThreads                         = 13              {product}           

CMSGCが間に合わなくてFull GCが発生してしまっている、もしくはFull GCにこそなっていないもののヒープ最大近くまで消費しているケースでG1GCにスイッチするともっとFull GCが起こる。G1GCはそもそも高スループットGCという位置付けではない。

重要なのはポーズタイムだ。CMSでポーズタイムが問題になっている、ヒープはいくらでも増やせるがCMSでこれ以上ヒープ増やすとポーズタイムも一緒に増えて困るよね、というときにG1GCの出番だ。

Java 7の結果

  • CMS
    • max used: 11.2G
    • max pause: 0.998 secs
  • G1GC
    • max used: 14.7G
    • max pause: 0.318 secs

Java 8の結果

  • CMS
    • max used: 11.7G
    • max pause: 0.627 secs (ParNew is slow, CMS is 0.191 secs)
  • G1GC
    • max used: 18.7G
    • max pause: 0.409 secs

Java 7でデータ量を倍にする

  • CMS
    • ヒープ使用量20GBくらいになるけどふつうにさばける、ポーズタイムは相変わらず1秒前後
  • G1GC
    • 16秒停止するFull GCが4回発生するのでダメ

まとめ

Java 8のCMSなんでこんなクソ速いの?予想外でした。

まとめ追記

Java 8のCMSフェーズはクソ速かったんだけど、見直してみたら速いだろうと思っていて結果から除外していたParNewが遅かったので実際のmax pauseは0.627 secsだった。というわけでヒープが十分であればG1GCのほうがポーズタイムは低下するよ、というありきたりな結論。あと、G1GCの方が累計pauseが短く、アプリケーションによりCPUリソースが割り当たるので高速。