このセクションでは、エラー・ログを使用してクラッシュの原因を見つける方法を説明するいくつかの例を示し、その原因に応じて問題をトラブルシューティングするためのいくつかのヒントを提示します。
エラー・ログのヘッダーは、エラーのタイプと問題のあるフレームを示し、スレッド・スタックは現在のスレッドおよびスタック・トレースを示しています。「ヘッダー形式」を参照してください。
クラッシュには次の原因が考えられます。
問題のあるフレームがネイティブ・ライブラリであることが致命的エラー・ログで示されている場合は、ネイティブ・コードまたはJava Native Interface (JNI)ライブラリ・コード内にバグが存在する可能性があります。クラッシュが他の原因で発生した可能性ももちろんありますが、最初はライブラリとコア・ファイルまたはクラッシュ・ダンプを分析するのが適切です。致命的なエラー・ログのヘッダーからの例5-1の抜粋を検討してください。
例5-1 致命的エラー・ログのヘッダーからの抜粋
# An unexpected error has been detected by HotSpot Virtual Machine: # # SIGSEGV (0xb) at pc=0x417789d7, pid=21139, tid=1024 # # Java VM: Java HotSpot(TM) Server VM (6-beta2-b63 mixed mode) # Problematic frame: # C [libApplication.so+0x9d7]
この場合は、ライブラリlibApplication.so
内で実行されているスレッドでSIGSEGV
が発生しました。
場合によっては、ネイティブ・ライブラリ内のバグがJava VMコード内のクラッシュとして表れます。_thread_in_vm
状態で(つまり、Java VMコードで実行されているとき)、JavaThread
が失敗した例5-2のクラッシュを検討してください。
例5-2 クラッシュの例
# An unexpected error has been detected by HotSpot Virtual Machine: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x08083d77, pid=3700, tid=2896 # # Java VM: Java HotSpot(TM) Client VM (1.5-internal mixed mode) # Problematic frame: # V [jvm.dll+0x83d77] --------------- T H R E A D --------------- Current thread (0x00036960): JavaThread "main" [_thread_in_vm, id=2896] : Stack: [0x00040000,0x00080000), sp=0x0007f9f8, free space=254k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [jvm.dll+0x83d77] C [App.dll+0x1047] <========= C/native frame j Test.foo()V+0 j Test.main([Ljava/lang/String;)V+0 v ~StubRoutines::call_stub V [jvm.dll+0x80f13] V [jvm.dll+0xd3842] V [jvm.dll+0x80de4] V [jvm.dll+0x87cd2] C [java.exe+0x14c0] C [java.exe+0x64cd] C [kernel32.dll+0x214c7] :
この場合、問題のあるフレームはVMフレームですが、スレッド・スタックは、App.dll
内のネイティブ・ルーチンが(おそらくJNIを使って)VM内に呼び出されたことを示しています。
ネイティブ・ライブラリでのクラッシュを解決する最初の手順は、クラッシュが発生したネイティブ・ライブラリのソースを調べることです。
ネイティブ・ライブラリがアプリケーションによって提供されている場合は、ネイティブ・ライブラリのソース・コードを調べます。-Xcheck:jni
オプションをコマンド行に追加してアプリケーションを実行することで、JNIコードに関する多くの問題を特定できます。「-Xcheck:jniオプション」を参照してください。
ネイティブ・ライブラリが別のベンダーから提供され、アプリケーションで使用されている場合は、このサードパーティ・アプリケーションに対するバグ・レポートを提出し、致命的エラー・ログの情報を提供します。
クラッシュが発生したネイティブ・ライブラリがJava Runtime Environment (JRE)の一部(awt.dllやnet.dllなど)である場合は、ライブラリまたはAPIのバグが発生した可能性があります。その場合は、できるだけ多くのデータを収集し、ライブラリ名を示してバグまたはレポートを提出してください。JREライブラリは、JREディストリビューションのjre/libまたはjre/binディレクトリにあります。「バグ・レポートの提出」を参照してください。
ネイティブ・アプリケーション・ライブラリ内のクラッシュをトラブルシューティングするには、ネイティブ・デバッガをコア・ファイルまたはクラッシュ・ダンプ(利用可能な場合)に接続します。ネイティブ・デバッガは、OSに応じてdbx
、gdb
、またはwindbg
です。「オペレーティング・システムのネイティブ・ツール」を参照してください。
コンパイル済みコードでクラッシュが発生したことが致命的エラー・ログで示されている場合は、不正なコードを生成するコンパイラ・バグが発生した可能性があります。問題のあるフレームのタイプがJ
(コンパイル済みのJavaフレームを意味する)である場合は、コンパイル済みコードでクラッシュが発生したと認識できます。例5-3は、このようなクラッシュを示しています。
例5-3 コンパイル済みコードでのクラッシュ
# An unexpected error has been detected by HotSpot Virtual Machine: # # SIGSEGV (0xb) at pc=0x0000002a99eb0c10, pid=6106, tid=278546 # # Java VM: Java HotSpot(TM) 64-Bit Server VM (1.6.0-beta-b51 mixed mode) # Problematic frame: # J org.foobar.Scanner.body()V # : Stack: [0x0000002aea560000,0x0000002aea660000), sp=0x0000002aea65ddf0, free space=1015k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) J org.foobar.Scanner.body()V [error occurred during error reporting, step 120, id 0xb]
注意: 完全なスレッド・スタックは取得できません。「error occurred during error reporting」(エラー報告中にエラーが発生しました)という出力行は、スタック・トレースを取得しようとして問題が発生したこと(スタックの破損を示している可能性がある)を意味します。
コンパイラを切り替える(たとえば、HotSpot Server VMの代わりにHotSpot Client VMを使用する、またはその逆)か、クラッシュを引き起こしたメソッドをコンパイルから除外することによって、問題を一時的に回避できる可能性があります。この具体例ではコンパイラを切り替えられない可能性があります(これは64ビットのサーバーVMから取ったものであり、32ビットのクライアントVMへの切替えはできない可能性があるため)。
使用可能な回避方法の詳細は、「HotSpotコンパイラ・スレッドまたはコンパイル済みコードでのクラッシュの回避」を参照してください。
致命的エラー・ログの出力に、現在のスレッドがCompilerThread0
、CompilerThread1
、またはAdapterCompiler
という名前のJavaThread
であることが示されている場合は、コンパイラのバグが発生した可能性があります。この場合は、コンパイラを切り替える(たとえば、HotSpot Server VMの代わりにHotSpot Client VMを使用する、またはその逆)か、クラッシュを引き起こしたメソッドをコンパイルから除外することによって、問題を一時的に回避しなければいけないことがあります。
使用可能な回避方法の詳細は、「HotSpotコンパイラ・スレッドまたはコンパイル済みコードでのクラッシュの回避」を参照してください。
致命的エラー・ログの出力に、現在のスレッドがVMThread
であることが示されている場合は、THREAD
セクションでVM_Operation
を含む行を探してください。VMThread
は、HotSpot VMの特別なスレッドです。VM内でガベージ・コレクション(GC)などの特殊なタスクを実行します。VM_Operation
によって、操作がGCであることが示唆された場合は、ヒープの破損などの問題が発生した可能性があります。
GCの問題以外にも、ヒープ内のオブジェクト参照を不整合または不正な状態にしておく他の何か(コンパイラやランタイムのバグなど)が問題である可能性も等しくあります。この場合は、環境に関する情報をできるだけ多く収集し、可能な回避策を試してください。問題がGCに関連する場合は、GCの構成を変更することによって問題を一時的に回避できることがあります。
使用可能な回避方法の詳細は、「ガベージ・コレクション中のクラッシュの回避」を参照してください。
Java言語コード内でスタック・オーバーフローが発生すると、通常は違反したスレッドがjava.lang.StackOverflowError
例外をスローします。一方、CおよびC++はスタックの終わりを越えて書込みを行い、スタック・オーバーフローを引き起こします。これは、プロセスが終了する致命的エラーです。
HotSpot実装では、Javaメソッドがスタック・フレームをC/C++ネイティブ・コード(つまり、ユーザー・ネイティブ・コードおよび仮想マシン自体)と共有します。Javaメソッドは、スタック空間を越えることなくネイティブ・コードを呼び出せるように、スタックの終わりに向かって一定距離のスタック空間が使用可能であるかどうかをチェックするコードを生成します。このスタックの終わりまでの距離を「シャドウ・ページ」と呼びます。シャドウ・ページのサイズは、プラットフォームに応じて3-20ページです。この距離は調整可能であるため、デフォルトより長い距離を必要とするネイティブ・コードを含むアプリケーションは、シャドウ・ページのサイズを増やすことができます。シャドウ・ページを増やすためのオプションは-XX:StackShadowPages=
nです(nはプラットフォームのデフォルトのシャドウ・ページより大きくします)。
アプリケーションでセグメンテーション障害が発生したときにコア・ファイルまたは致命的エラー・ログ・ファイル(付録Aを参照)が生成されなかったか、Windows上でSTACK_OVERFLOW_ERROR
が発生したか、または「An irrecoverable stack overflow has occurred」(回復不能なスタック・オーバーフローが発生しました)というメッセージが表示された場合、これはStackShadowPages
の値を超過したため、より多くの空間が必要であることを示します。
StackShadowPages
の値を増やす場合は、-Xss
パラメータを使用してデフォルトのスレッド・スタック・サイズも増やす必要があることがあります。デフォルトのスレッド・スタック・サイズを増やすと、作成できるスレッドの数が減る可能性があるため、スレッド・スタック・サイズの値は慎重に選択してください。スレッド・スタック・サイズは、プラットフォームによって256 KBから1024 KBまで様々です。
例5-4 スタック・オーバーフロー例外
# An unexpected error has been detected by HotSpot Virtual Machine: # # EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x10001011, pid=296, tid=2940 # # Java VM: Java HotSpot(TM) Client VM (1.6-internal mixed mode, sharing) # Problematic frame: # C [App.dll+0x1011] # --------------- T H R E A D --------------- Current thread (0x000367c0): JavaThread "main" [_thread_in_native, id=2940] : Stack: [0x00040000,0x00080000), sp=0x00041000, free space=4k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [App.dll+0x1011] C [App.dll+0x1020] C [App.dll+0x1020] : C [App.dll+0x1020] C [App.dll+0x1020] ...<more frames>... Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) j Test.foo()V+0 j Test.main([Ljava/lang/String;)V+0 v ~StubRoutines::call_stub
例5-4から次の情報を解釈できます。
例外はEXCEPTION_STACK_OVERFLOW
です。
スレッドの状態は_thread_in_native
で、スレッドがネイティブ・コードまたはJNIコードを実行していることを意味します。
スタック情報では、空き領域は4 KB (Windowsシステムの単一ページ)のみです。さらに、スタック・ポインタ(sp
)はスタックの終わり(0x00040000
)に近い0x00041000
です。
ネイティブ・フレームの出力は、再帰的なネイティブ関数がこの場合の問題であることを示しています。出力の...
という表記は、追加のフレームが存在するが、出力されなかったことを示します。出力は100フレームまでに制限されています。