このリリースのJDK 8では、JVMおよびJavaアプリケーションに関する問題を診断するため、Java Mission Control、Java Flight Recorderおよびjcmd
ユーティリティが導入されています。診断機能を強化し、パフォーマンスのオーバーヘッドを削減するには、以前のjstack
ユーティリティのかわりに最新のユーティリティjcmd
の使用をお薦めします。
次の項では、jstack
ユーティリティによるトラブルシューティング手法について説明します。
jstack
コマンド行ユーティリティは、指定されたプロセスまたはコア・ファイルに接続し、仮想マシンに接続されたすべてのスレッド(JavaスレッドやVM内部スレッドも含む)のスタック・トレースを出力するほか、オプションでネイティブ・スタック・フレームも出力します。このユーティリティではデッドロック検出も実行されます。
このユーティリティは、jsadebugd
デーモンを使ってリモート・マシン上のプロセスやコア・ファイルを照会することもできます。注意: この場合、出力に時間がかかります。
すべてのスレッドのスタック・トレースは、デッドロックやハングアップなど、いくつかの問題の診断に役立つ可能性があります。
-l
オプションは、所有可能なシンクロナイザをヒープ内で探してjava.util.concurrent.locks
に関する情報を出力するように、ユーティリティに指示します。このオプションがない場合、スレッド・ダンプにはモニターの情報のみが含まれます。
jstack
pidオプションの出力は、アプリケーション・コンソール(標準入力)で[Ctrl]+[\]を押すか、プロセスにQUITシグナルを送信した場合に得られるものと同じです。出力例については、「Ctrl+Breakハンドラ」を参照してください。
スレッド・ダンプは、プログラム内でThread.getAllStackTraces
メソッドを使って、またはデバッガ内ですべてのスレッド・スタックを出力するデバッガ・オプション(jdb
サンプル・デバッガの場合はwhere
コマンド)を使って取得することもできます。
jstack
ユーティリティの詳細は、jstack
コマンドのマニュアル・ページを参照してください。
ハングアップ・プロセスが原因でjstack
pidコマンドが応答しない場合は、例2-29のように、-F
オプションを使用してスタック・ダンプを強制することができます(Oracle SolarisおよびLinuxオペレーティング・システムのみ)。
例2-29 jstackユーティリティによるスタック・ダンプの強制
$ jstack -F 8321
Attaching to process ID 8321, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Deadlock Detection:
Found one Java-level deadlock:
=============================
"Thread2":
waiting to lock Monitor@0x000af398 (Object@0xf819aa10, a java/lang/String),
which is held by "Thread1"
"Thread1":
waiting to lock Monitor@0x000af400 (Object@0xf819aa48, a java/lang/String),
which is held by "Thread2"
Found a total of 1 deadlock.
Thread t@2: (state = BLOCKED)
Thread t@11: (state = BLOCKED)
- Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)
Thread t@10: (state = BLOCKED)
- Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)
Thread t@6: (state = BLOCKED)
Thread t@5: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=-1107318896 (Interpreted frame)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=116 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=132 (Interpreted frame)
- java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame)
Thread t@4: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait() @bci=2, line=485 (Interpreted frame)
- java.lang.ref.Reference$ReferenceHandler.run() @bci=46, line=116 (Interpreted frame)
コア・ダンプからスタック・トレースを取得するには、例2-30のように、コア・ファイルでjstack
コマンドを実行します。
jstack
ユーティリティは、混合スタックの出力に使用することもできます(つまり、Javaスタックの他にネイティブ・スタック・フレームも出力できます)。ネイティブ・フレームとは、VMコードやJNI/ネイティブ・コードに関連付けられたC/C++フレームのことです。
混合スタックを出力するには、例2-31のように、-m
オプションを使用します。
例2-31 jstackユーティリティによる混合Javaスタック
$ jstack -m 21177
Attaching to process ID 21177, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Deadlock Detection:
Found one Java-level deadlock:
=============================
"Thread1":
waiting to lock Monitor@0x0005c750 (Object@0xd4405938, a java/lang/String),
which is held by "Thread2"
"Thread2":
waiting to lock Monitor@0x0005c6e8 (Object@0xd4405900, a java/lang/String),
which is held by "Thread1"
Found a total of 1 deadlock.
----------------- t@1 -----------------
0xff2c0fbc __lwp_wait + 0x4
0xff2bc9bc _thrp_join + 0x34
0xff2bcb28 thr_join + 0x10
0x00018a04 ContinueInNewThread + 0x30
0x00012480 main + 0xeb0
0x000111a0 _start + 0x108
----------------- t@2 -----------------
0xff2c1070 ___lwp_cond_wait + 0x4
0xfec03638 bool Monitor::wait(bool,long) + 0x420
0xfec9e2c8 bool Threads::destroy_vm() + 0xa4
0xfe93ad5c jni_DestroyJavaVM + 0x1bc
0x00013ac0 JavaMain + 0x1600
0xff2bfd9c _lwp_start
----------------- t@3 -----------------
0xff2c1070 ___lwp_cond_wait + 0x4
0xff2ac104 _lwp_cond_timedwait + 0x1c
0xfec034f4 bool Monitor::wait(bool,long) + 0x2dc
0xfece60bc void VMThread::loop() + 0x1b8
0xfe8b66a4 void VMThread::run() + 0x98
0xfec139f4 java_start + 0x118
0xff2bfd9c _lwp_start
----------------- t@4 -----------------
0xff2c1070 ___lwp_cond_wait + 0x4
0xfec195e8 void os::PlatformEvent::park() + 0xf0
0xfec88464 void ObjectMonitor::wait(long long,bool,Thread*) + 0x548
0xfe8cb974 void ObjectSynchronizer::wait(Handle,long long,Thread*) + 0x148
0xfe8cb508 JVM_MonitorWait + 0x29c
0xfc40e548 * java.lang.Object.wait(long) bci:0 (Interpreted frame)
0xfc40e4f4 * java.lang.Object.wait(long) bci:0 (Interpreted frame)
0xfc405a10 * java.lang.Object.wait() bci:2 line:485 (Interpreted frame)
... more lines removed here to reduce output...
----------------- t@12 -----------------
0xff2bfe3c __lwp_park + 0x10
0xfe9925e4 AttachOperation*AttachListener::dequeue() + 0x148
0xfe99115c void attach_listener_thread_entry(JavaThread*,Thread*) + 0x1fc
0xfec99ad8 void JavaThread::thread_main_inner() + 0x48
0xfec139f4 java_start + 0x118
0xff2bfd9c _lwp_start
----------------- t@13 -----------------
0xff2c1500 _door_return + 0xc
----------------- t@14 -----------------
0xff2c1500 _door_return + 0xc
先頭にアスタリスク(*)が付いているフレームがJavaフレーム、先頭にアスタリスクが付いていないフレームがネイティブC/C++フレームです。
このユーティリティの出力をc++filt
によってパイプで連結すると、C++分解シンボル名を分解解除できます。Java HotSpot VMはC++言語で開発されているため、jstack
ユーティリティはJava HotSpotの内部関数のC++分解シンボル名を出力します。
c++filt
ユーティリティは、SUNWspro
(Oracle Solarisオペレーティング・システムの場合)やgnu
(Linuxの場合)というネイティブC++コンパイラ・スイートとともに配布されます。