macosでJVMのスレッドダンプを取得する

JVMのこと、詳しくなりたくって、でも何もできずにいる自分がただそこにいるだけで、悔しくて泣きたくて。
そんな気持ちを最近持ったので、勉強しはじめた。

とりあえずjavaをインストールする

ORACLEのインストールガイドを読むのが一番。
MacでのJavaのインストール方法

インストール完了後、こんな感じでバージョンを確認できたらよさげ。

$java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

javaのプログラムを起動する

とりあえず簡単なプログラムを起動させて、立ち上がっているプロセスを確認したい。
ただ、ずっと起動しぱなっしのプロセスにしてあげる必要があるので、BufferedReader というやつを使って、入力完了するまでプロセスが死なないようにした。

import java.io.*;
public class HelloWorld {
  public static void main (String[] args) throws IOException
    {
        InputStreamReader is = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(is);
        System.out.println("何か入力してください.");
        String str = br.readLine();
        System.out.println(str + "が入力されました.");
    }
}

HelloWorld.java として保存して、 javac HelloWorld.java , java HelloWorld を実行すると実行される。

javaプロセス起動中にスレッドダンプを取得

プログラムを実行すると、 何か入力してください. と出たまま入力せずに別のコンソールから起動中のプロセスを確認する。

$ps aux | grep java
user           34577   0.0  0.0  2432804    776 s021  S+    2:27AM   0:00.00 grep java
user           34573   0.0  0.3  6026488  22852 s019  S+    2:27AM   0:00.16 /usr/bin/java HelloWorld

ちゃんと立ち上がったままになってて良い感じ。

次にスレッドダンプを取得。

$jps
34582 Jps
34573 HelloWorld

jpsコマンドで、pidに紐づいたjavaの実行プログラムがリストで取れるっぽい。
さらに jstack コマンドでpidを指定するとそのプロセスのスレッドダンプを出力できる。

$jstack 34420
2017-05-17 02:13:46
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):

"Attach Listener" #9 daemon prio=9 os_prio=31 tid=0x00007fc815083800 nid=0x1307 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Service Thread" #8 daemon prio=9 os_prio=31 tid=0x00007fc815025800 nid=0x4903 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #7 daemon prio=9 os_prio=31 tid=0x00007fc816008800 nid=0x4703 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 daemon prio=9 os_prio=31 tid=0x00007fc81582c800 nid=0x4503 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=31 tid=0x00007fc815871800 nid=0x4303 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007fc815871000 nid=0x4103 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007fc815857800 nid=0x3103 in Object.wait() [0x000070000dd8e000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x0000000795588ec8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
...

あとはよさげに

jstack 34420 > hoge.log

とかしてあげるとよい。

なお、スレッドダンプの読み方も調べてみたけど語るには知識がなさすぎるので、参考になった記事を共有するに留めておくことにします。

enk.hatenablog.com

Java書かないのでまったくここらへんのことわからないけど、少しずつこうやって知見を貯めていきたい。