プロセスのダンプファイルを取得してデバッグする方法
たとえばハングしているプロセスのダンプファイルを取得して別の環境で解析する方法について記述する。
Windowsの場合
ダンプファイルの取得方法
タスクマネージャーからプロセスを選択してダンプファイルを作成する。
しばらくすると、一時フォルダにDMPファイルが作成される。
ダンプファイルをVisualStudioでデバッグする方法
VisualStudioを使用することでDMPファイルを開いてデバッグを行える。
.NETFrameworkを使用している場合
.NETFrameworkを使用していない場合
.NETFrameworkを使用している場合は「マネージドのみでデバッグ」または「混合でデバッグ」を選択する。
.NETFrameworkを使用していない場合は「ネイティブのみでデバッグ」を選択する。
「スレッド」ウィンドウにはプロセスのスレッドの一覧が表示される。
「呼び出し履歴」ウィンドウには選択したスレッドの呼び出し履歴が表示される。
呼び出し履歴を選択することで、その箇所のコードが表示される。
これらを利用することでデッドロックしている箇所をしらべることができる。
GDBが使える環境の場合
ダンプファイルの取得方法
gdbを起動して以下のコマンドを実行する。
attach プロセスID
gcore 出力ファイル名
detach
quit
ダンプファイルをgdbでデバッグする方法
起動方法
gdb 実行ファイル名 ダンプファイル
スレッドの一覧を表示する方法
Debugging programs with multiple threads
(gdb) info threads
Id Target Id Frame
6 Thread 0x7f24db490740 (LWP 11479) 0x00007f24da859f47 in pthread_join ()
from /lib64/libpthread.so.0
5 Thread 0x7f24d847f700 (LWP 11484) 0x00007f24da548e2d in nanosleep ()
from /lib64/libc.so.6
4 Thread 0x7f24d8c80700 (LWP 11483) 0x00007f24da548e2d in nanosleep ()
from /lib64/libc.so.6
3 Thread 0x7f24d9481700 (LWP 11482) 0x00007f24da548e2d in nanosleep ()
from /lib64/libc.so.6
2 Thread 0x7f24d9c82700 (LWP 11481) 0x00007f24da548e2d in nanosleep ()
from /lib64/libc.so.6
* 1 Thread 0x7f24da483700 (LWP 11480) 0x00007f24da548e2d in nanosleep ()
from /lib64/libc.so.6
スレッドの切り替え方法
(gdb) thread 5
[Switching to thread 5 (Thread 0x7f24d847f700 (LWP 11484))]
呼び出し履歴の表示
backtraceコマンドを使用すると現在のスレッドの呼び出し履歴が確認できる。
(gdb) bt
#0 0x00007f24da548e2d in nanosleep () from /lib64/libc.so.6
#1 0x00007f24da579704 in usleep () from /lib64/libc.so.6
#2 0x00000000004012e6 in f(int) ()
#3 0x00000000004029f0 in void std::_Bind_simple<void (*(int))(int)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) ()
#4 0x00000000004028fd in std::_Bind_simple<void (*(int))(int)>::operator()()
()
#5 0x0000000000402896 in std::thread::_Impl<std::_Bind_simple<void (*(int))(int)> >::_M_run() ()
#6 0x00007f24db03a070 in ?? () from /lib64/libstdc++.so.6
#7 0x00007f24da858dd5 in start_thread () from /lib64/libpthread.so.0
#8 0x00007f24da581ead in clone () from /lib64/libc.so.6
Javaの場合
ヒープダンプを作成する
jmapコマンドでヒープダンプを作成することが可能。
jmap -dump:format=b,file=<file-path> <pid>
作成したヒープダンプからメモリの使用状況を調べることができる。
ヒープダンプを解析するにはjvisualvmなどを利用する。
スレッドダンプを作成する
jstackコマンドを使用するとスレッドダンプが作成することが可能。
jstack -l <pid>
現時点のスレッドの情報を取得することができ、デッドロックをしていると以下のようになる。
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x0000000003aa8138 (object 0x00000007018084d8, a ChopSticks),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x0000000003aa8088 (object 0x0000000701800bf0, a ChopSticks),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at Human.eat(Human.java:35)
- waiting to lock <0x00000007018084d8> (a ChopSticks)
- locked <0x0000000701800bf0> (a ChopSticks)
at Human.run(Human.java:18)
"Thread-0":
at Human.eat(Human.java:35)
- waiting to lock <0x0000000701800bf0> (a ChopSticks)
- locked <0x00000007018084d8> (a ChopSticks)
at Human.run(Human.java:18)
Found 1 deadlock.
コアダンプからヒープダンプとスレッドダンプを作成する
タスクマネージャーで作成したjavaのコアダンプはjvisualvmで解析することができる。
jvisualvmを起動してVMのコアダンプからjavaのダンプファイルを開いてヒープダンプやスレッドダンプを作成可能になっている。
jvisualvmで起動中のプロセスからヒープダンプやスレッドダンプを作成する
jvisualvmは起動中のプロセスから直接スレッドダンプやヒープダンプを作成することができる。