74
Java 9 でででででででででで jcmd で jhsdb でで でで @YaSuenag https://www.flickr.com/photos/falcon_33/8988705269 #jdt2016_4A

Java 9で進化する診断ツール

Embed Size (px)

Citation preview

Page 1: Java 9で進化する診断ツール

Java 9 で進化する診断ツールjcmd と jhsdb

末永 恭正  @YaSuenag

https://www.flickr.com/photos/falcon_33/8988705269

#jdt2016_4A

Page 2: Java 9で進化する診断ツール

おことわり

Oracle と Java は、 Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。文中の社名、商品名等は各社の商標または登録商標である場合があります。

• JDK 9 の HotSpot 開発リポジトリでお話しします• jdk9/hs/hotspot   Changeset: 11272:3d94e9193472• GA では変更になっている部分があるかもしれません

• Linux x64 が前提です

Page 3: Java 9で進化する診断ツール

自己紹介• 末永 恭正(すえなが やすまさ) @YaSuenag• SIer で Java やってるサンデープログラマー• OpenJDK jdk9 committer• IcedTea committer

• HeapStats 作ってますhttp://icedtea.classpath.org/wiki/HeapStats/jp

Page 4: Java 9で進化する診断ツール

Java 9 時代の解析ツール突然ですが

jcmd

jhsdb&

Page 5: Java 9で進化する診断ツール

適用範囲

情報収集・設定変更プロセスハング解析

コア解析

jcmdjhsdb

Page 6: Java 9で進化する診断ツール

jcmd の機能拡張情報収集の決定版!

Page 7: Java 9で進化する診断ツール

jcmd 一本で!• もう jstack や jmap などは使いません!• 例えば jstack

• Java Platform, Standard Edition Troubleshooting Guide より• http://

docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr016.html#BABFCHDE

It is suggested to use the latest utility, jcmd instead of the previous jstack utility for enhanced diagnostics and reduced performance overhead.

Page 10: Java 9で進化する診断ツール

Java 9 から登場したコマンドコマンド 内容VM.log ログ出力設定とローテーションの実行VM.print_touched_methods 実行されたメソッドの一覧表示VM.classloader_stats クラスローダに関する情報の表示VM.stringtable StringTable ( String#intern() した文字列や解決し

たクラス名が入っているテーブル)の概要表示、ダンプVM.symboltable SymbolTable (メソッド名等)の概要表示、ダンプVM.class_hierarchy Java ヒープ中のクラス階層構造の表示VM.info java プロセスの詳細情報、およびマシン情報の表示VM.dynlibs ロードされている共有ライブラリの出力VM.set_flag フラグ( -XX オプション)の変更

VM ドメイン

Page 11: Java 9で進化する診断ツール

Java 9 から登場したコマンドコマンド 内容Compiler.directives_clear JIT コンパイラへの指示をすべてクリアCompiler.directives_remove 一番最後の JIT コンパイラへの指示を削除Compiler.directives_add JIT コンパイラへの指示を JSON 形式での指定Compiler.directives_print JIT コンパイラへの現在の指示内容の表示Compiler.codecache コードキャッシュの概要の表示Compiler.codelist コードキャッシュの内容表示Compiler.queue JIT コンパイラのコンパイル待ちキューにあるメソッドの

表示

Compiler ドメイン

Page 12: Java 9で進化する診断ツール

Java 9 から登場したコマンドコマンド 内容ManagementAgent.status JMX エージェントの状態表示JVMTI.agent_load JVMTI エージェントのロードJVMTI.data_dump JVMTI のデータダンプ要求( DataDumpRequest )発

行GC.finalizer_info ファイナライザ実行待ちキューに入っているクラス情報

の表示GC.heap_info Java ヒープの概要表示

その他

Page 13: Java 9で進化する診断ツール

新しいコマンドの使用例

Page 14: Java 9で進化する診断ツール

ログの出力設定忘れちゃった!!

Page 15: Java 9で進化する診断ツール

VM.log• JEP 158: Unified JVM Logging

• http://openjdk.java.net/jeps/158• JVM 中の様々なイベントをロギングできます

• 起動中のプロセスに対するログ出力設定、ローテーション実行

Page 16: Java 9で進化する診断ツール

例: GC ログを出力する$ jcmd 1234 VM.log output="file=gc.log" \ output_options="filecount=5,filesize=10m" \ what="gc=debug" \ decorators="time,level"

オプション名 内容output 出力先

”#< 数字 >” を指定すると既存の output に対する変更を意味する

output_options 出力オプションwhat タグやログレベルの設定decorators ログデコレーションの設定

Page 17: Java 9で進化する診断ツール

強制ログローテーション• 全ログ出力の中で、以下の条件に合致するものをローテート

1. 出力先がファイル2. filecount オプションが有効

• Java 8 までの GC.rotate_log コマンドは消えました• GC ログ自体がなくなりました

$ jcmd 1234 VM.log rotate

Page 18: Java 9で進化する診断ツール

ちなみに…$ jcmd 1234 VM.log list1234:Available log levels: off, trace, debug, info, warning, errorAvailable log decorators: time (t), uptime (u), timemillis (tm), uptimemillis (um), timenanos (tn), uptimenanos (un), hostname (hn), pid (p), tid (ti), level (l), tags (tg)Available log tags: add, age, alloc, arguments, annotation, barrier, biasedlocking, bot, breakpoint, census, class, classhisto, cleanup, compaction, constraints, constantpool, coops, cpu, cset, data, defaultmethods, dump, ergo, exceptions, exit, freelist, gc, heap, humongous, ihop, iklass, init, itables, jni, jvmti, liveness, load, loader, logging, mark, marking, methodcomparator, metadata, metaspace, mmu, modules, monitorinflation, monitormismatch, nmethod, normalize, objecttagging, obsolete, oopmap, os, pagesize, path, phases, plab, promotion, preorder, protectiondomain, ref, redefine, refine, region, remset, purge, resolve, safepoint, scavenge, scrub, stacktrace, start, startuptime, state, stats, stringdedup, stringtable, stackmap, subclass, survivor, sweep, task, thread, tlab, time, timer, update, unload, verification, verify, vmoperation, vtables, workgangDescribed tag combinations: logging: Logging for the log framework itselfLog output configuration:#0: stdout all=warning uptime,level,tags#1: stderr all=off uptime,level,tags#2: gc.log gc=debug filecount=5,filesize=20M level,tags

JDK-8153074UL: Show output option in VM.log jcmd

Page 19: Java 9で進化する診断ツール

障害解析に必要な情報を簡単に収集させたい

Page 20: Java 9で進化する診断ツール

VM.info• クラッシュ時のエラーリポートと同等の詳細ログを収集

• スレッド• メモリマッピング• プロセッサのスペック 等

• HotSpot の状態だけでなく、マシンスペックや OS の確認にも便利!

Page 21: Java 9で進化する診断ツール

出力例$ jcmd 1234 VM.info1234:## JRE version: Java(TM) SE Runtime Environment (9.0+119) (build 9-ea+119)# Java VM: Java HotSpot(TM) 64-Bit Server VM (9-ea+119, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)

--------------- S U M M A R Y ------------

Command Line: LongSleep

Host: Intel(R) Core(TM) i3-2367M CPU @ 1.40GHz, 2 cores, 1G, Fedora release 23 (Twenty Three)Time: Mon May 23 20:32:22 2016 JST elapsed time: 16 seconds (0d 0h 0m 16s)

--------------- P R O C E S S ---------------

Heap address: 0x00000000e0e00000, size: 498 MB, Compressed Oops mode: 32-bitNarrow klass base: 0x0000000000000000, Narrow klass shift: 3Compressed class space size: 1073741824 Address: 0x0000000100000000:

Page 22: Java 9で進化する診断ツール

ヤバい!オプションつけ忘れた…

Page 23: Java 9で進化する診断ツール

VM.set_flag• jinfo -flag の代替• 設定できるオプションは非推奨( -XX )の一部のみ

$ jcmd 1234 VM.flags -all | grep -E 'manageable|product_rw' intx CMSAbortablePrecleanWaitMillis = 100 {manageable} intx CMSTriggerInterval = -1 {manageable} intx CMSWaitDuration = 2000 {manageable} bool HeapDumpAfterFullGC = false {manageable} bool HeapDumpBeforeFullGC = false {manageable} bool HeapDumpOnOutOfMemoryError = false {manageable} ccstr HeapDumpPath = {manageable} uintx MaxHeapFreeRatio = 70 {manageable} uintx MinHeapFreeRatio = 40 {manageable} bool PrintClassHistogram = false {manageable} bool PrintConcurrentLocks = false {manageable}

Page 24: Java 9で進化する診断ツール

例:フラグ有効化• HeapDumpOnOutOfMemoryError を有効にする

$ jcmd 1234 VM.set_flag HeapDumpOnOutOfMemoryError true1234:Command executed successfully$ jcmd 1234 VM.flags1234:-XX:CICompilerCount=2 -XX:ConcGCThreads=1 -XX:G1HeapRegionSize=1048576-XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=33554432 -XX:MarkStackSize=4194304-XX:MaxHeapSize=522190848 -XX:MaxNewSize=312475648 -XX:MinHeapDeltaBytes=1048576-XX:NonNMethodCodeHeapSize=5824844 -XX:NonProfiledCodeHeapSize=122916698-XX:ProfiledCodeHeapSize=122916698 -XX:ReservedCodeCacheSize=251658240-XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC

JDK-8155936Boolean value should be set 1/0 or true/false via VM.set_flag jcmd

Page 25: Java 9で進化する診断ツール

JIT を細かく制御して問題発生を予防しましょうね

Page 26: Java 9で進化する診断ツール

Compiler.directives_add• JEP 165: Compiler Control

• JIT コンパイラに対する細かな制御を実現• 定義ファイルは JSON で記述

• -XX:CompilerDirectivesFile で指定するものと同じ

Page 27: Java 9で進化する診断ツール

JSON の例• String#hashCode() の C2 だけ無効化してみる

[ { match: ["*String.hashCode"],

c2: { Exclude: true } }]

Page 28: Java 9で進化する診断ツール

Compiler.directives_add

$ jcmd 1234 Compiler.directives_add compiler-directive.json1234:1 compiler directives added

Page 29: Java 9で進化する診断ツール

設定の確認• Compiler.directives_print で確認できます

$ jcmd 1234 Compiler.directives_print1234:

Directive: matching: *String.hashCode c1 directives: inline: - Enable:false Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:false CloneMapDebug:false DoReserveCopyInSuperWordDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

c2 directives: inline: - Enable:true Exclude:true BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:false CloneMapDebug:false DoReserveCopyInSuperWordDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

Enable :ディレクティブの明示的設定Exclude: JIT 除外設定

Page 30: Java 9で進化する診断ツール

オレのアプリ、どれぐらい JIT の恩恵受けてるんだ?

Page 31: Java 9で進化する診断ツール

Compiler.codelist• コードキャッシュ内に存在するメソッドを一覧表示

$ jcmd 1234 Compiler.codelist1234:53 4 java.lang.String.hashCode()I [0x00007fd2cd776090, 0x00007fd2cd776200 - 0x00007fd2cd776398]

コンパイルID

コンパイルレベル( Tiered Compilation )

メソッド名nmethod開始アドレス コード開始アドレス

コード終了アドレス

Page 32: Java 9で進化する診断ツール

Tiered Compilation を詳しく知りたい方は…• JDK 8 JVM Improvements

• Java Day Tokyo 2014 で David Buck氏が講演• http://

otndnld.oracle.co.jp/ondemand/javaday2014/pdf/C2-JavaDay-304328.pdf

Page 33: Java 9で進化する診断ツール

さて、診断ツール仕込むか

Page 34: Java 9で進化する診断ツール

JVMTI.agent_load• JVMTI エージェントライブラリのロードを行う

• ネイティブエージェント、 Java エージェントのどちらも可能• エージェントはライブアタッチに対応している必要あり

• ネイティブエージェント: Agent_OnAttach() の実装• Java エージェント: agentmain() の実装

Page 35: Java 9で進化する診断ツール

Before• Attach API を使うしかありませんでした…

• 要 Java プログラミング• http://

docs.oracle.com/javase/8/docs/jdk/api/attach/spec/index.html

Page 36: Java 9で進化する診断ツール

After• HeapStats をアタッチしてみる

Page 37: Java 9で進化する診断ツール

After• HeapStats をアタッチしてみる

0 の意味:Agent_OnAttach() の戻り値http://docs.oracle.com/javase/jp/8/docs/platform/jvmti/jvmti.html#onattach

Page 38: Java 9で進化する診断ツール

動かしてみる• JVMTI.data_dump

Page 39: Java 9で進化する診断ツール

ヒープの状況をざっくり知りたい

Page 40: Java 9で進化する診断ツール

GC.heap_info• 各メモリ領域の容量、最大容量、使用量を出力

• Java ヒープ• Metaspace

• スレッドダンプ出力時に出てくるものと同じ• -XX:PrintHeapAtSIGBREAK

$ jcmd 1234 GC.heap_info1234: garbage-first heap total 32768K, used 1024K [0x00000000e0e00000, 0x00000000e0f00100, 0x0000000100000000) region size 1024K, 2 young (2048K), 0 survivors (0K) Metaspace used 3332K, capacity 4486K, committed 4864K, reserved 1056768K class space used 328K, capacity 386K, committed 512K, reserved 1048576K

Page 41: Java 9で進化する診断ツール

jcmd の仕組み

Page 42: Java 9で進化する診断ツール

PerfCounter.print• jvmstat Performance Counter を参照する

• /tmp/hsperfdata_<ユーザー名 >/<pid>• バイナリファイルをただパースするだけ

Page 43: Java 9で進化する診断ツール

hsperfdata の構造プロローグ(ファイルヘッダ) エントリ

Page 44: Java 9で進化する診断ツール

その他のコマンド• Attach Listener へ jcmd コマンドを送出

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

Page 45: Java 9で進化する診断ツール

詳しくはコチラ• Serviceability Tools の裏側

• http://www.slideshare.net/YaSuenag/serviceability-tools

Page 46: Java 9で進化する診断ツール

jcmd の弱点ターゲットプロセスがハングしたら動かない!

※PerfCounter.print 以外

Page 47: Java 9で進化する診断ツール

jhsdbServiceability Agent Launcher

Page 48: Java 9で進化する診断ツール

jhsdb• Java 9 から新しく入った診断ツール• SA の Launcher

• (CL)HSDB の呼び出しが簡単に!• コア解析、プロセス解析の心強い味方!

Page 49: Java 9で進化する診断ツール

SA とは?• Serviceability Agent• 各種ツールの -F オプションやコア解析などで動作するのが SA

• Java 9 からは各種ツールで SA が使えなくなりました!• JDK-8155091: Remove SA related functions from tmtools

• Red Hat系 Linux なら OpenJDK の debuginfo パッケージ必須• ネイティブデバッガ同様の仕組みでプロセスから情報収集

• Linux なら ptrace(2) でプロセスにアタッチ• プロセスハングも関係なし!

Page 51: Java 9で進化する診断ツール

jhsdb でできることツール名 概要clhsdb コマンドライン版 HotSpot デバッガhsdb GUI 版 HotSpot デバッガjstack SA 版 jstackjmap SA 版 jmapjinfo SA 版 jinfojsnap hsperfdata の読み取り

Page 52: Java 9で進化する診断ツール

jhsdb でできないこと• デバッグサーバへの接続はできません

• jsadebugd• HSDB だけは起動後にリモートデバッグサーバに接続できます

• デバッグサーバになることもできません

Page 53: Java 9で進化する診断ツール

注意点• オプションは長い名前で指定する

• ex. jstack -m は jhsdb jstack --mixed

• jhsdb jinfo ではフラグ設定はできない• フラグ設定したい場合は jcmd VM.set_flag で

Page 54: Java 9で進化する診断ツール

新ツール: jsnap• 実は昔からありました

• sun.jvm.hotspot.tools.JSnap

• hsperfdata の中に入っているパフォーマンスカウンタを読み込む SA• 以下の問題を直して正式デビュー!

• 一部のカウンタしか読み込めない• コアからデータを抜けない

JDK-8151815Could not parse core image with JSnap.

Page 55: Java 9で進化する診断ツール

jsnap がなかったら…• コアからカウンタを読み込むのがタイヘン

(gdb) x/g ((G1CollectedHeap *)Universe::_collectedHeap)->_g1mm->_full_collection_counters->_time ->_valuep0x7f8c6884b960: 15535194

例: Full GC の累計実行時間を出してみる( jstat の FGCT相当)

15535194÷1000000000≒0.015 (sec)

Page 56: Java 9で進化する診断ツール

GC アルゴリズムによってカウンタへのポインタまでの辿り方違うのかよ…

OpenJDK のソースなんて読みたくねーよ…

Page 57: Java 9で進化する診断ツール

jsnap があれば…• コマンド一発!

$ $JAVA_HOME/bin/jhsdb jsnap --exe $JAVA_HOME/bin/java --core core.6937 --all | \ grep -a -e sun.gc.collector.1.time -e sun.os.hrt.frequencysun.gc.collector.1.time=15535194 tick(s)sun.os.hrt.frequency=1000000000 Hz

15535194÷1000000000≒0.015 (sec)

この実現のために JDK-8151815ガンバってます!

Page 58: Java 9で進化する診断ツール

クラッシュ解析で困ることHotSpot ( C++ )の世界と

Java の世界を結びつけるのがタイヘン

Page 59: Java 9で進化する診断ツール

HSDB

Page 60: Java 9で進化する診断ツール

最強デバッガ: HSDB• 実は昔からありました

• sun.jvm.hotspot.HSDB

• HotSpot の世界をわかりやすく解析できるツール• Swing の GUI ツール• コマンドライン版は CLHSDB

• ディスアセンブルもサポート• 要 hsdis

Page 61: Java 9で進化する診断ツール

コアを食わせてみる• File

• Open HotSpot core file

Page 62: Java 9で進化する診断ツール

クラッシュしたスレッドを見つける• Java Threads

• ゴミ箱アイコン• クラッシュスレッドのスタックメモリを表示• hs_err を吐くようなエラーのみ検知可能

Page 63: Java 9で進化する診断ツール

コールスタックを確認してみる• Java Threads

• スレッド選択• 紙(?)アイコン

Page 64: Java 9で進化する診断ツール

オブジェクトのメモリを確認する• Tools

• Inspector• oop のアドレスを入力

Page 65: Java 9で進化する診断ツール

ディスアセンブルしてみる• Java Stack Trace

• pc をクリック• 要 hsdis

Page 66: Java 9で進化する診断ツール

hsdis 利用時に気を付けること

Project Kenai からのダウンロードはやめましょう!

Page 67: Java 9で進化する診断ツール

なぜダウンロードはダメなのか?• 古いから

• 一番新しいものでも 6年以上前• 最新の CPU命令をデコードできない

https://kenai.com/projects/base-hsdis/downloads

Page 68: Java 9で進化する診断ツール

Project Kenai のもの Fedora23 でビルドしたものStubRoutines::updateBytesCRC32

※OracleJDK 8u92 Linux x64 で確認( -XX:+UnlockDiagnosticVMOptions -XX:+PrintStubCode )

Page 69: Java 9で進化する診断ツール

hsdis のビルドFedora23 x64 の場合$ dnf download --source binutils

$ rpm -ivh <binutils>

$ cd ~/rpmbuild/SPECS$ rpmbuild -bp binutils.spec

$ cd <OpenJDK src>/hotspot/src/share/tools/hsdis$ make BINUTILS=~/rpmbuild/BUILD/<binutils> ARCH=amd64

$ ls build/linux-amd64/hsdis-amd64.sobuild/linux-amd64/hsdis-amd64.so

binutils のSRPM取得

SRPM展開

hsdis のビルド

hsdis 本体

Page 70: Java 9で進化する診断ツール

hsdis のデプロイ• ~ Java 8

• $JAVA_HOME/jre/lib/amd64• Java 9~

• $JAVA_HOME/lib/amd64

Page 71: Java 9で進化する診断ツール

でも、やっぱり最後は…

GDB

Page 72: Java 9で進化する診断ツール

怖くない GDB• バックトレースをとるだけでも解析のヒントになる

• クラッシュしたポイントは JNI?• Java Bug System に既知バグがある?

• https://bugs.openjdk.java.net/• debuginfo が入っていれば C/C++ のコードで見れる!

• 必ずしもアセンブラと格闘しなくてよい

Page 73: Java 9で進化する診断ツール

Java 9 時代の解析ツール最後にもう 1度

jcmd

jhsdb&

Page 74: Java 9で進化する診断ツール