第7章 JDK/JREのチューニング
7.4 異常発生時の原因振り分け
本項では、異常が発生したときに、原因を振り分ける方法を説明します。
7.4.1 java.lang.StackOverflowErrorがスローされた場合
StackOverflowErrorがスローされた場合、スタックオーバーフローが原因です。
スタックのサイズをチューニングしてください。
スタックのチューニング方法は、“7.5.1 スタックのチューニング”を参照してください。
7.4.2 java.lang.OutOfMemoryErrorがスローされた場合
本節では、OutOfMemoryErrorがスローされた場合、考えられる原因とその対処方法を説明します。
なお、FJVMを使用でOutOfMemoryErrorがスローされた場合に出力されるメッセージ情報については、“メモリ領域不足事象発生時
のメッセージ出力機能の強化”も参照してください。
■想定される原因(メモリリーク)
VMがガーベジコレクションを繰り返しても、時間の経緯とともにメモリ消費量が増大していく場合、プログラム中メモリリークを起こして いる可能性があります。
メモリリークの結果、Javaのヒープ不足が発生しOutOfMemoryErrorがスローされる場合があります。
この場合、ガーベジコレクションのログを採取して、Javaヒープの消費状況を確認してください。ガーベジコレクションのログを採取す る方法は、“7.3.1 ガーベジコレクションのログ出力”を参照してください。
■想定される原因(Javaヒープ不足)
通常、OutOfMemoryErrorは、Javaヒープ不足が原因でスローされます。
ガーベジコレクションのログを採取して、Javaヒープの消費状況を確認してください。
Javaヒープの空き容量がないことが確認されたら、Javaヒープをチューニングしてください。
ガーベジコレクションのログを採取する方法は、“7.3.1 ガーベジコレクションのログ出力”を参照してください。
Javaヒープのチューニング方法は、“7.5.2 Javaヒープのチューニング”を参照してください。
■想定される原因(ユーザ空間不足)
多量のスレッドを生成して、多量のスタックがユーザ空間内に割り当てられ、ユーザ空間不足になった場合、次のOutOfMemoryError がスローされる、あるいはエラーメッセージとして表示を行いプロセスが終了します。
java.lang.OutOfMemoryError: unable to create new native thread
また、JavaヒープやOSの仮想メモリに余裕があるにもかかわらず、ユーザ空間内にメモリを確保できなかった場合、次の OutOfMemoryErrorが出力されプログラムが終了します。
java.lang.OutOfMemoryError: requested サイズ bytes 制御名. Out of swap space?
サイズ: 確保できなかったメモリの大きさ
制御名: メモリが確保できなかったJava VMの制御名(該当情報がある場合にだけ表示)
ユーザ空間が不足している場合は、Javaヒープまたはスタックのサイズを小さくするなどのチューニングを行ってください。
スタックのサイズをチューニングする方法は、“7.5.1 スタックのチューニング”を参照してください。
Javaヒープのチューニング方法は、“7.5.2 Javaヒープのチューニング”を参照してください。
なお、仮想メモリに余裕がある場合は、Javaプロセスを複数起動して、プロセス多重度を上げる方法もあります。J2EEアプリケーションまたは
JavaEEアプリケーションの場合、J2EEまたはJavaEEのチューニングを行ってください。J2EEまたはJavaEEのチューニング方法の詳細
は、それぞれのマニュアルを参照してください。
■想定される原因(仮想メモリ不足)
仮想メモリが不足してスレッドが生成できない場合、次のOutOfMemoryErrorがスローされる、あるいはエラーメッセージとして表示 を行いプロセスが終了します。
java.lang.OutOfMemoryError: unable to create new native thread
また、OSの仮想メモリが不足した場合、次のOutOfMemoryErrorが出力されプログラムが終了します。
java.lang.OutOfMemoryError: requested サイズ bytes 制御名. Out of swap space?
サイズ: 確保できなかったメモリの大きさ
制御名: メモリが確保できなかったJava VMの制御名(該当情報がある場合にだけ表示)
仮想メモリが不足した場合は、他の不要なプロセスを終了して仮想メモリに余裕を持たせるか、物理メモリ(RAM)またはスワップファイ ルを拡張して仮想メモリを増やすようにチューニングを行ってください。
7.4.3 ハングアップ(フリーズ)した場合
本節では、Javaプロセスが残っているにもかかわらず、プログラムが無応答になった場合、考えられる原因とその対処方法を説明しま す。
■想定される原因(デッドロック)
デッドロックが発生した場合、そのスレッドが停止されます。
ハングアップしたときに、スレッドダンプを採取して、デッドロックがないかどうかを確認してください。
スレッドダンプの採取方法および解析方法の詳細は、“7.3.3 スレッドダンプ”を参照してください。
■想定される原因(ガーベジコレクション)
ガーベジコレクションが発生すると、ガーベジコレクションが終了するまでの間、Javaアプリケーションのすべてのスレッドが停止されま す。
これにより、Javaアプリケーションがハングアップしたかのように見える場合があります。
ガーベジコレクションのログを採取して、ガーベジコレクションが動作したタイミングを照合してください。ガーベジコレクションが原因で 無応答のような現象になる場合は、Javaヒープをチューニングして、ガーベジコレクションの動作具合を改善してください。
ガーベジコレクションのログを採取する方法は、“7.3.1 ガーベジコレクションのログ出力”を参照してください。
Javaヒープのチューニング方法は、“7.5.2 Javaヒープのチューニング”を参照してください。
■想定される原因(JNI処理の異常)
JNI経由でJava以外の言語で開発したネイティブモジュールと連携する際、JNIの使用方法を誤ると、ハングアップの原因となります。
このようなときは、“-Xcheck:jni”オプションを指定して、JNI処理でメッセージが出力されないかどうかを確認してください。“ -Xcheck:jni”オプションの詳細は、“7.3.5 JNI処理異常時のメッセージ出力”を参照してください。
JNI処理に誤りがなくても、JNIモジュールで異常終了またハングアップが発生すると、Javaアプリケーションがハングアップする場合が あります。たとえば、スレッドアンセーフな関数を使用している場合は、注意が必要です。
スレッドアンセーフな関数の例
次の関数を使用したときに、ハングした事例があります。
・ vfork
7.4.4 プロセスが消滅(異常終了)した場合
本節では、何の痕跡も残さずに突然プロセスが消滅した場合に、考えられる原因とその対処方法を説明します。
■想定される原因(スタックオーバーフロー)
FJVMには、スタックオーバーフロー検出時にメッセージを出力する機能を備えています。FJVMログを分析することにより、スタック
オーバーフローが発生したかどうかを確認することができます。FJVMログの分析方法は、“7.2.8 スタックオーバーフロー検出時のメッ セージ出力機能”を参照してください。
スタックオーバーフローが発生したことを確認できた場合、該当するスタックのサイズをチューニングしてください。スタックのチューニ ング方法は、“7.5.1 スタックのチューニング”を参照してください。
通常、スタックオーバーフローが発生した場合、java.lang.StackOverflowErrorがスローされ、ワトソン博士が検知してユーザダンプお よびワトソンログを出力します。
しかし、OSが高負荷状態になったり、スタックオーバーフロー発生時のスタック残量が少なかったりすると、OSからFJVMにもワトソン 博士にも制御が渡らないまま、痕跡を残さずにプロセスが消滅することがあります。
したがって、プロセスが消滅した原因が不明な場合は、スタックのサイズを拡張して、現象が改善できるかどうかを確認してください。
スタックのサイズを拡張しても改善できない場合は、別の原因を調査してください。
なお、ワトソン博士の説明は、“7.3.4 クラッシュダンプ・コアダンプ”を参照してください。
■想定される原因(長時間コンパイル処理の検出機能による終了) FJVMの“長時間コンパイル処理の検出機能”による終了の可能性があります。
詳細は、“7.2.10 長時間コンパイル処理の検出機能”を参照してください。
Javaアプリケーションを“-XX:CompileTimeout”オプションで起動した場合は、標準出力にFJVMからのメッセージが出力されていな
いかどうかを確認してください。
■想定される原因(シグナルハンドラ)
Java VM以外のモジュールで、シグナルハンドラを登録した場合、Javaアプリケーションが正常に動作せずに、異常終了することがあ ります。詳細は、“7.2.11.2 異常終了時のシグナルハンドラ情報”を参照してください。
FJVMを使用している場合は、FJVMログにシグナルハンドラ情報が出力されますので、それを確認してください。
■想定される原因(JNI処理の異常)
JNI経由でJava以外の言語で開発したネイティブモジュールと連携する際、JNIの使用方法を誤ると、プロセス消滅の原因となります。
このようなときは、“-Xcheck:jni”オプションを指定して、JNI
処理でメッセージが出力されないかどうかを確認してください。“-Xcheck:jni”オプションの詳細は、“7.3.5 JNI処理異常時のメッセージ出力”を参照してください。
JNI処理に誤りがなくても、ネイティブモジュールで異常終了またハングアップが発生すると、Javaアプリケーションのプロセスが消滅
する場合があります。たとえば、スレッドアンセーフな関数を使用している場合は、注意が必要です。
スレッドアンセーフな関数の例