まじめにJVMチューニング: 第3回 方針をたててパラメータをいじってみる

2014-01-29

さて、前回までで、ログからフルGC(及び高負荷なコンカレントGC)が発生していることはわかりました。
で、このチューニングの目的は、GCによるマシンへの負担を低減することにあります。

まず「なぜGCが発生するのか?」と「jvmがどうやってメモリ管理を行っているのか?」を知らないとチューニングのしようがないのですが、これらについては、下記に詳しく記載されていたのでリンクをはっておきます。

で、これらをふまえて・・・
一口にチューニングと言ってもいくつかのアプローチをとることができます。

  1. とにかくOld領域がいっぱいにならないようにマイナーGC回数を増やしてNew領域でやりくりする
  2. フルGCが発生するのはしようがないと諦めて、フルGC発生時の停止時間を短くする
  3. GCアルゴリズムを変更する(第4回でやります)

上記3つのそれぞれの方向からアプローチしてみます。

3-1. とにかくOld領域がいっぱいにならないように・・・

ということで、Eden領域、Survivor領域、Old領域の割合をいろいろ変えてみます。

  1. New:Old=1:1
  2. New:Old=1:2
  3. New:Old=1:4

  1. Eden:Su0:Su1=8:1:1
  2. Eden:Su0:Su1=4:1:1
  3. Eden:Su0:Su1=2:1:1

の組み合わせでいろいろ試してみました。

実際に渡したパラメータはこんな感じ。

パターン1. b×1(New:Old=1:2, Eden:Su0:Su1=8:1:1)


-XX:PermSize=128M -XX:MaxPermSize=128M
-Xms3584M -Xmx3584M
-Xloggc:/var/log/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:MaxTenuringThreshold=32
-XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90

gc.cms#1.t

パターン2. a×1(New:Old=1:1, Eden:Su0:Su1=8:1:1)


-XX:PermSize=128M -XX:MaxPermSize=128M
-Xms3584M -Xmx3584M
-Xloggc:/var/log/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:MaxTenuringThreshold=32
-XX:NewRatio=1 -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90

gc.cms#5.t

パターン3. a×3(New:Old=1:1, Eden:Su0:Su1=2:1:1)


-XX:PermSize=128M -XX:MaxPermSize=128M
-Xms3584M -Xmx3584M
-Xloggc:/var/log/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:MaxTenuringThreshold=32
-XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:TargetSurvivorRatio=90

gc.cms#8.t

指定したパラメータの内容については下記のブログに詳しく載っていました。

また余談ですが、負荷は

でかけました。

上記3つをピックアップしてみましたが、それぞれ波形が違うことが見て取れます。

maxのフルGC時間で比較すると、a×1(Old:New=1:1, Eden:Su0:Su1=8:1:1)が比較的良好なことがわかります。

3-2. フルGCが発生するのはしようがないと諦めて、フルGC発生時の停止時間を短くする

そもそも、フルGCの発生を完全に抑制することはできません。
なので、3-2.ではフルGCが発生するのはしようがないと割り切り、停止時間を短くするアプローチを取ってみます。

フルGCをインクリメンタルモードで動かしてみます。
イマドキのマシンは複数コア搭載が当たり前なので、アプリケーションを動かしていないコアをGCに使います。
また、大量のGCを一気に行うのではなく、細切れにちょびっとづつGCを行い、停止時間を短くします。

パラメータ例:


-XX:PermSize=128M -XX:MaxPermSize=128M
-Xms3584M -Xmx3584M
-Xloggc:/var/log/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:MaxTenuringThreshold=32
-XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90
-XX:+UseParNewGC
-XX:+CMSClassUnloadingEnabled
-XX:+CMSPermGenSweepingEnabled
-XX:+CMSIncrementalMode
-XX:+CMSIncrementalPacing
-XX:CMSIncrementalDutyCycleMin=0
-XX:+CMSParallelRemarkEnabled

で、インクリメンタルモードでも

  1. New:Old=1:1
  2. New:Old=1:2
  3. New:Old=1:4

  1. Eden:Su0:Su1=8:1:1
  2. Eden:Su0:Su1=4:1:1
  3. Eden:Su0:Su1=2:1:1

の組み合わせを試してみました。

gc.cms#13.t

インクリメンタルモードを指定したときと、そうでないとで波形に大きな違いがあることがわかります。

次回、GCアルゴリズムの変更を試してみます。
GCアルゴリズムを変えてみる

2018-04-21 追記.
@kuro_m88 にご指摘頂き、 NewRatioのNew:Old比が逆になっているのを修正しました。
ご迷惑をおかけしました m(_ _*)m


こちらの動画で詳しいチューニングのやり方も解説しています。

スクリーンショット 2015-08-24 10.01.11

VisualVMでjavaプロセスを可視化してみよう part1