Javaパフォーマンス改善 - Full GCの原因とその解決方法について

2011/12/09 17:34Update
TAGS: GC | FullGC | メモリ | Java | パフォーマンス | チューニング | ヒープ

Javaパフォーマンス改善につながるヒープ領域、GC、Full GC、Full GCの回避策などについて解説します。

■ヒープ領域について


ヒープ領域は
◇ 若い世代(New 領域)
  ※New領域はさらにEden領域、Survivor(From領域、To領域)という3つの領域に分割されています。
◇ 古い世代 (Old 領域) :寿命の長いオブジェクトがこの領域に配置されます。
があります。

ヒープ領域のほか、クラスのメタ情報を格納するPermanent 領域もあります。

■GCについて


GCは、Garbage Collection(ガベージ・コレクション)の略称で、メモリ領域の開放を行う役割を担います。
「Scavenge GC」:NEW領域を対象とした短時間で終了するガベージ・コレクションで、New 領域が不足した場合に実行されます。
    ※Scavenge GCの実行時間が0.1秒未満がベスト
「Full GC」:Old 領域が不足した場合実行されます。 Full GCが行われている間は、他の処理ができなくなり、システムは一時的に停止し応答しません。
    ※Full GCの実行時間が1秒未満がベスト


■Full GCだと思われる現象


数秒~数十秒間でWebシステムは一時停止して応答がない状態で、Full GCの可能性が高いと思われます。
Java VMの仕組み上で、Full GCによるシステムの一時停止現象は一般に「Stop the World」と呼ばれています。


■Full GCの原因


JavaヒープのOld 領域かPermanent 領域が一杯になっている(枯渇)時にFull GC が発生します。
※JDK1.5.0+であればPermanent領域は一杯になることはないようで Old 領域を疑った方がよいかもしれません。

■Full GCの確認


JVMの起動パラメータにGCを出力するように設定することで、GCやFull GCログが出力されますので、Full GCがどの頻度で行われたかを確認できます。

◇設定例:
-verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
※-XX:+HeapDumpOnOutOfMemoryError (JDK1.5+)

◇Full GCの出力例:
228.004: [Full GC 228.004: [Tenured: 168230K->167535K(1699072K), 1.2345678 secs]
    167459K->64535K(1038336K), [Perm : 53247K->53247K(53248K)], 1.3357874 secs]

■Full GCの回避策


JavaヒープのOld領域を枯渇させないようにすること。
◇プログラムを見直す
1)オブジェクトをできるだけ使い回さない。使いまわされると、Old 領域に割り当てられる可能性も高くなりますので、Full GC が発生しやすくなります。
2)オブジェクトの寿命を短くにする。セッション理由は同上2)
3)長く利用する使いまわしオブジェクト(セッションや接続プールなど)の数やサイズを減らす:Old領域を満杯にならないようにする。
 ※セッションタイムアウト時間は必要以上になっていないか
 ※セッションに必要以上(数、サイズ)のオブジェクトが格納されていないか
 ※アプリケーション スコープのオブジェクトは必要以上(数、サイズ)に格納されていないか

◇JavaVMの設定を見直す
1)一時(短命)オブジェクトは多い場合、New 領域を大きめ取る。
2)使いまわしオブジェクトは多い場合、Old領域を大きめ取る。
3)Scavenge GCは
New領域が大きすぎる可能性があるので、-Xmn(-XX:NewSize)、-XX:MaxNewSizeを減らす。


◇※GC関連の基本的なJVMオプション
-Xms    ヒープ領域の初期値
-Xmx    ヒープ領域の最大値。一般的に、-Xmsと同値にする
-Xmn    NEW領域(Eden、From、To)の初期値。
-XX:NewSize    New 領域の初期値。同-Xmn
-XX:MaxNewSize    New 領域の最大値。一般的に、-XX:NewSizeと同値にする。
-XX:PermSize    Permanent 領域の初期値
-XX:MaxPermSize    Permanent 領域の最大値。一般的に、-XX:PermSizeと同値にする。

-XX:NewRatio    New 領域と Old 領域の比率
-XX:SurvivorRatio    New 領域と Survivor 領域の比率。SurvivorRatio=Eden÷Survivor

-verbose:gc(-Xloggc:出力先)    GCログ出力指定
-XX:+PrintGCTimeStamps    GCログにタイムスタンプ(Java起動時からの経過時間)出力
-XX:+PrintGCDetails 詳細なGCログを出力
-XX:+PrintClassHistogram SIGQUITシグナル(kill -3 pid)受信時にヒープ統計情報を出力。-verbose:gc(-Xloggc:出力先)と併用必須。
-XX:+HeapDumpOnOutOfMemoryError    OutOfMemoryError発生時にヒープダンプを出力 (JDK1.5+)

-XX:+UseParallelGC    マルチコアCPUまたは複数CPUの場合は、パラレルGCをマルチスレッドで実行を有効にする
※-XX:PermSize/-XX:MaxPermSize:-Xms/-Xmx範囲に含まれないことをご理解ください。

◇※NEW領域の調整について
NEW領域:-Xmnオプションを用いてNEW領域(Eden、From、To)のサイズを指定します。
NEW領域の割合は、最大ヒープ・サイズ(-Xmxオプション)の1/4から1/2の間で設定することが一般的となります。


◇システム構成を見直す
1)システムを冗長化する
2)Full GCさせないアプリサーバで対応

などの方法があります。

設定例:
export CATALINA_OPTS="-server -Xmx256M -Xms256M -XX:NewSize=128M -XX:MaxNewSize=128M -XX:SurvivorRatio=2 -Xloggc:/var/log/gc.log"

-Xms=1024m -Xmx=1024m -XX:PermSize=128m -XX:MaxPermSize=128m -XX:NewSize=320m -XX:MaxNewSize=320m -XX:SurvivorRatio=2 -XX:TargetSurvivorRatio=80


メモリ関連ツール




◇ヒープダンプ情報出力ツール
・jmap:ヒープダンプを行うツール
・jconsole
・hprof
・jstack:スレッドダンプを行うツール
※jps:JavaのPIDを確認するツール
※jinfo:Java VM の構成情報を参照、設定するためのツール


◇プロファイラ ツール
・visualvm
・NetBeans Profiler
・jprofiler

◇統計&分析ツール
・Eclipse Memory Analyzer
・HeapAnalyzer
・HAT
・jstat
・jhat
・gcLogViewer
・SAP Memory Analyerツール
・IBMR HeapAnalyzer


参考資料


Java OutOfMemoryError対策
java.lang.OutOfMemoryError: PermGen space及びJava PermGenについて
ガーベジ・コレクション:GC ( Garbage Collection ) についての簡単な説明と調査方法
Javaメモリ、GCチューニングとそれにまつわるトラブル対応手順まとめ - 日記のような何か
Full GC発生を抑止するメモリ管理技術「PDF」
@IT:チューニングのためのJava VM講座(後編)
「Java のヒープサイズ」についての簡単な説明
ise0615 blog: JAVAヒープサイズ・GCチューニングのまとめ
肥え続けるTomcatと胃を痛めるトラブルハッカー (2/3) - @IT
Java HotSpot VM Options
Oracle JRockit JVM のチューニングの初歩
@IT:事例に学ぶWebシステム開発のワンポイント(6)
@IT:事例に学ぶWebシステム開発のワンポイント(9)

有关作者
Syboos.jp編集長AJavaやオープンソース情報の執筆、Webサイトの開発や運営全般の業務に携わる。

Sponsored Link


Comments

用户名 (required)

Email (will not be published) (required)

URL

Evaluation