Slide 1

Slide 1 text

あなたと スレッドダンプ 2014/9/20 第八回 #渋谷java Kotaro Noguchi (@enk_enk)

Slide 2

Slide 2 text

スレッドダンプ、 取ってますか?

Slide 3

Slide 3 text

僕は取ってません

Slide 4

Slide 4 text

スレッドダンプ、 読んでますか?

Slide 5

Slide 5 text

僕は読んでません

Slide 6

Slide 6 text

スレッドダンプは むずかしそう

Slide 7

Slide 7 text

いや、 スレッドダンプは むずかしくない

Slide 8

Slide 8 text

いや、 スレッドダンプは むずかしくない と思いたい

Slide 9

Slide 9 text

ので

Slide 10

Slide 10 text

あなたと スレッドダンプ スレッドダンプはこわくない

Slide 11

Slide 11 text

スレッドダンプ とはなにか

Slide 12

Slide 12 text

スレッドダンプとはなにか • Java のスレッドのスナップショット • 取得した瞬間、JVM 上でどのような処 理が実行されているのかを調査するこ とができる • 各スレッドの名前、状態、スタックトレー ス等を一覧できる

Slide 13

Slide 13 text

何の役に立つ のか

Slide 14

Slide 14 text

スレッドダンプは 何の役に立つのか • プログラムが遅いとき・フリーズしたとき • そんなときでも、スレッドダンプは取れる • プログラムが遅い・フリーズしている場 合も、JVM 自体は動作しているため ※ • JVM 最高、C++ ではこうはいかない • スレッドダンプを読めば、プログラムが 遅い原因・フリーズした原因がわかる • かもしれない ※ JVM 自体が異常な状態にある場合は取得できないかもしれませんが、そう そうあることではない

Slide 15

Slide 15 text

スレッドダンプは 何の役に立つのか • プログラムがクラッシュしたとき • 自動的にスレッドダンプが出力される • クラッシュの原因調査に役立つ • 少なくともどのメソッドの実行中に クラッシュしたかはわかる

Slide 16

Slide 16 text

スレッドダンプは 何の役に立つのか • プログラムの動作への影響が少ない • ので、本番環境でも取得できちゃった りする

Slide 17

Slide 17 text

スレッドダンプ はこわくない

Slide 18

Slide 18 text

スレッドダンプの 取り方

Slide 19

Slide 19 text

スレッドダンプの取り方 - Windows 編(コンソール) • コンソールに対して Ctrl + Break • 可能な場合は、起動時に出力をファイル にリダイレクトしておくと読むのが楽です • リダイレクトしていない場合は、コマンド プロンプトのプロパティで「画面のバッ ファサイズ」を大きくすること • そうしないと頭が切れます…… $ [実行ファイル] > console.log 2>&1

Slide 20

Slide 20 text

スレッドダンプの取り方 - Windows 編(コンソール) • コンソールに対して Ctrl + Break • 可能な場合は、起動時に出力をファイル にリダイレクトしておくと読むのが楽です • リダイレクトしていない場合は、コマンド プロンプトのプロパティで「画面のバッ ファサイズ」を大きくすること • そうしないと頭が切れます…… $ [実行ファイル] > console.log 2>&1

Slide 21

Slide 21 text

スレッドダンプの取り方 - Windows 編(サービス起動) • jstack を使用する • まずは jps でプロセス ID を調べる • 対象のプロセスがわかったら $ jps $ jstack <プロセス ID> > c:¥tmp¥jstack.txt

Slide 22

Slide 22 text

スレッドダンプの取り方 - Windows 編(サービス起動) • jstack で「プロセスにアクセスできませ ん」 • PsExec の出番ですね 参考 : dstnフォーラム - サービス起動で運用している場合でもスレッドダンプを取 る方法はないでしょうか? • なお jstack は JRE には含まれない (JDK に入っている)ので注意 psexec -s jstack PID > c:¥tmp¥jstack.txt

Slide 23

Slide 23 text

スレッドダンプの取り方 - UNIX 編 • プロセス ID を調べてから kill -3 • Windows 編(サービス起動)で紹介した jstack ももちろん利用可能 $ ps -ef | grep java $ kill -3 <プロセス ID>

Slide 24

Slide 24 text

スレッドダンプの取り方 - ポイント • スレッドダンプの取得では、あいだを開け ながら何度か取得しましょう • 数秒おきとか数分おきとか、場合に応 じて • スレッドの状態遷移を調べることが大 事

Slide 25

Slide 25 text

スレッドダンプ はこわくない ような気がしてきた

Slide 26

Slide 26 text

スレッドダンプの 読み方

Slide 27

Slide 27 text

スレッドダンプの読み方 - 組成 "http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x182d3880> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at java.lang.Object.wait(Object.java:485) at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458) - locked <0x182d3880> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484) at java.lang.Thread.run(Thread.java:662)

Slide 28

Slide 28 text

スレッドダンプの読み方 - 組成 "http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x182d3880> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at java.lang.Object.wait(Object.java:485) at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458) - locked <0x182d3880> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484) at java.lang.Thread.run(Thread.java:662) 1-2 行目は名前とか状態とか

Slide 29

Slide 29 text

スレッドダンプの読み方 - 組成 "http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x182d3880> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at java.lang.Object.wait(Object.java:485) at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458) - locked <0x182d3880> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484) at java.lang.Thread.run(Thread.java:662) 以降はスタックトレース

Slide 30

Slide 30 text

あれ、簡単っぽい ……?

Slide 31

Slide 31 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) スレッド名

Slide 32

Slide 32 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) デーモンスレッドならここに “daemon” て出る

Slide 33

Slide 33 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) スレッドの優先順位

Slide 34

Slide 34 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) スレッド ID

Slide 35

Slide 35 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) ネイティブスレッド ID

Slide 36

Slide 36 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) スレッド の状態

Slide 37

Slide 37 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) スレッド の状態(Thread.State にもとづく)

Slide 38

Slide 38 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4" daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) スレッド名 • なんかむずかしそうだけど、だいたいここ見 れば十分 スレッド ID スレッド の状態(Thread.State にもとづく)

Slide 39

Slide 39 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッド名から、どんなスレッドかあたりがつ けられる • JVM の内部スレッドもいろいろあったり する • CompilerThread, Finalizer, Reference Handler, VM Thread…… 等 • スレッドの異様な多さに惑わされな いようにしましょう

Slide 40

Slide 40 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッド ID(tid)で、任意のスレッドの状態 を追跡できる • スレッドダンプを何度か取得したら、ス レッド ID をキーにしてスレッドを追跡でき る • 侍 というツールがこの方面で非常に有 用らしいです

Slide 41

Slide 41 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッドの状態を見れば、スレッドの状態が わかる!! • あたりまえですが……。

Slide 42

Slide 42 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッドの状態 : RUNNABLE • 元気に実行中 • ロックを取っている場合、スタックトレース中に こんなんが出ます • ちなみにこれは RUNNABLE じゃなくても 出ます(ロックを取った状態で、別のロック を待ってるとか……ありますよね) - locked <0x1113d330> (a java.lang.Object)

Slide 43

Slide 43 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッドの状態 : BLOCKED • ブロックされている(ロック取得待ち) • スタックトレース中にこんなんが出ます - waiting to lock <0x1113d330> (a java.lang.Object)

Slide 44

Slide 44 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッドの状態 : BLOCKED • ブロックされている(ロック取得待ち) • スタックトレース中にこんなんが出ます • あ、さっきのやつと <> 内がおんなじで すね……。 - waiting to lock <0x1113d330> (a java.lang.Object)

Slide 45

Slide 45 text

(さっきのスライド) • スレッドの状態 : RUNNABLE • 元気に実行中 • ロックを取っている場合、スタックトレース中に こんなんが出ます - locked <0x1113d330> (a java.lang.Object)

Slide 46

Slide 46 text

(さっきのスライド) • スレッドの状態 : RUNNABLE • 元気に実行中 • ロックを取っている場合、スタックトレース中に こんなんが出ます • こいつが解放されるのを待っていたのですね。 - locked <0x1113d330> (a java.lang.Object)

Slide 47

Slide 47 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッドの状態 : WAITING • 下記いずれかの状態で待機している • Object.wait(タイムアウトなし) • Thread.join(タイムアウトなし) • LockSupport.park • たとえば、wait の場合、スタックトレース中 にこんなんが出ます - waiting on <0x0a7348d8> (a java.lang.Object)

Slide 48

Slide 48 text

スレッドダンプの読み方 - 1 – 2 行目 • スレッドの状態 : TIMED_WAITING • 下記いずれかの状態で待機している • Object.wait(タイムアウトあり) • Thread.join(タイムアウトあり) • LockSupport.parkNanos • LockSupport.parkUntil • WAITING とだいたい同じですね。

Slide 49

Slide 49 text

スレッドダンプの読み方 - 1 – 2 行目 • なお、Thread.State については Javadoc でも丁寧に説明されています • 列挙型 Thread.State

Slide 50

Slide 50 text

スレッドダンプの読み方 - 1 – 2 行目 “http-7399-4” daemon prio=6 tid=0x0146a400 nid=0x29c in Object.wait() [0x2ff9f000] java.lang.Thread.State: WAITING (on object monitor) スレッド の状態 • スレッドの状態については、1 行め末尾の 情報も参考になると思います • たぶん……。

Slide 51

Slide 51 text

スレッドダンプの読み方 - 1 – 2 行目(補足) • 今回は Java 7 のスレッドダンプで説明した が、違う JVM だと、ちょっと様子が違う • たとえば、過去の JRockit とか……。 • でも、基本は同じ。必要なら差分だけグ グればなんとかなる(はず) • ちなみに JRockit については丁寧な解 説ページがあります • スレッド ダンプの使用

Slide 52

Slide 52 text

スレッドダンプの読み方 - 以降の行(スタックトレース) • そのスレッドでのメソッドの呼び出しスタック が並んでいる、ただのスタックトレースです • ふつうに読んでください • ただ、こういうのが挟まってくることには 注目 - locked <0x1113d330> (a java.lang.Object) - waiting to lock <0x1113d330> (a java.lang.Object)

Slide 53

Slide 53 text

これで

Slide 54

Slide 54 text

スレッドダンプ はこわくない

Slide 55

Slide 55 text

ですね。

Slide 56

Slide 56 text

あなたと スレッドダンプ, 今すぐ CTRL + BREAK 無料スレッドダンプの DUMP

Slide 57

Slide 57 text

参考文献 • プログラミング言語 Java 第 4 版 • スレッドの章があってスレッドの基礎がお さえられるのがよい • 増補改訂版 Java 言語で学ぶデザインパ ターン入門 マルチスレッド編 • Object.wait の少々ややこしい仕組みに ついて非常にわかりやすく解説されてい ます、WAITING がどういう状態なのか わからない方におすすめ

Slide 58

Slide 58 text

参考 Web ページ • jstack でスレッドダンプを取る - にょきにょきブログ • 現場にキく、Webシステムの問題解決ノウハウ(1):Java EEサーバからレスポンス返らず。何から調べる? (1/2) - @IT • Java - スレッドダンプの取り方 - #侍ズム • スローダウン、ハングを一発解決! スレッドダンプは トラブルシューティングの味方 • スレッド ダンプの使用 • 列挙型 Thread.State • サービス起動で運用している場合でもスレッドダンプを取る 方法はないでしょうか? - dstnフォーラム

Slide 59

Slide 59 text

最後に 宣伝

Slide 60

Slide 60 text

WE’RE HIRING!

Slide 61

Slide 61 text

WE’RE HIRING!

Slide 62

Slide 62 text

株式会社アプレッソは 開発者を募集しています • Java • たまに C#、JavaScript • Java できない人でも歓迎 • プログラミングできる人・できるようになれ る人なら!(ちなみに僕は 10 ヶ月前の 入社当時 Java できない人でした) • もちろん Java できる人も歓迎

Slide 63

Slide 63 text

株式会社アプレッソは 開発者を募集しています • 快適です

Slide 64

Slide 64 text

株式会社アプレッソは 開発者を募集しています • 快適です

Slide 65

Slide 65 text

株式会社アプレッソは 開発者を募集しています • 快適です • (色がへんなのは写真がへただからです ……) • 心おきなく Java が書けます • たのしいエンタープライズジャバ • DataSpider Servista(主力製品) • DataSpider BPM • PIMSYNC

Slide 66

Slide 66 text

株式会社アプレッソは 開発者を募集しています • Wantedly で募集してます • パッケージ開発エンジニア募集!SIer出 身の方大歓迎!! • パッケージ開発のエンジニアがどう働い ているか知りたい人、集まれ! • 個人ブログにもちょっと様子を書いています • パッケージ開発エンジニアを募集してい ます - この国では犬がコードを書いてい ます