Upload
yasumasa-suenaga
View
1.877
Download
3
Embed Size (px)
Citation preview
Java 9 で進化する診断ツールjcmd と jhsdb
末永 恭正 @YaSuenag
https://www.flickr.com/photos/falcon_33/8988705269
#jdt2016_4A
おことわり
Oracle と Java は、 Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。文中の社名、商品名等は各社の商標または登録商標である場合があります。
• JDK 9 の HotSpot 開発リポジトリでお話しします• jdk9/hs/hotspot Changeset: 11272:3d94e9193472• GA では変更になっている部分があるかもしれません
• Linux x64 が前提です
自己紹介• 末永 恭正(すえなが やすまさ) @YaSuenag• SIer で Java やってるサンデープログラマー• OpenJDK jdk9 committer• IcedTea committer
• HeapStats 作ってますhttp://icedtea.classpath.org/wiki/HeapStats/jp
Java 9 時代の解析ツール突然ですが
jcmd
jhsdb&
適用範囲
情報収集・設定変更プロセスハング解析
コア解析
jcmdjhsdb
jcmd の機能拡張情報収集の決定版!
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.
http://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/jstack.html#BABBIIJD
http://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/s11-troubleshooting_tools.html#sthref327
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 ドメイン
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 ドメイン
Java 9 から登場したコマンドコマンド 内容ManagementAgent.status JMX エージェントの状態表示JVMTI.agent_load JVMTI エージェントのロードJVMTI.data_dump JVMTI のデータダンプ要求( DataDumpRequest )発
行GC.finalizer_info ファイナライザ実行待ちキューに入っているクラス情報
の表示GC.heap_info Java ヒープの概要表示
その他
新しいコマンドの使用例
ログの出力設定忘れちゃった!!
VM.log• JEP 158: Unified JVM Logging
• http://openjdk.java.net/jeps/158• JVM 中の様々なイベントをロギングできます
• 起動中のプロセスに対するログ出力設定、ローテーション実行
例: 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 ログデコレーションの設定
強制ログローテーション• 全ログ出力の中で、以下の条件に合致するものをローテート
1. 出力先がファイル2. filecount オプションが有効
• Java 8 までの GC.rotate_log コマンドは消えました• GC ログ自体がなくなりました
$ jcmd 1234 VM.log rotate
ちなみに…$ 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
障害解析に必要な情報を簡単に収集させたい
VM.info• クラッシュ時のエラーリポートと同等の詳細ログを収集
• スレッド• メモリマッピング• プロセッサのスペック 等
• HotSpot の状態だけでなく、マシンスペックや OS の確認にも便利!
出力例$ 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:
ヤバい!オプションつけ忘れた…
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}
例:フラグ有効化• 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
JIT を細かく制御して問題発生を予防しましょうね
Compiler.directives_add• JEP 165: Compiler Control
• JIT コンパイラに対する細かな制御を実現• 定義ファイルは JSON で記述
• -XX:CompilerDirectivesFile で指定するものと同じ
JSON の例• String#hashCode() の C2 だけ無効化してみる
[ { match: ["*String.hashCode"],
c2: { Exclude: true } }]
Compiler.directives_add
$ jcmd 1234 Compiler.directives_add compiler-directive.json1234:1 compiler directives added
設定の確認• 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 除外設定
オレのアプリ、どれぐらい JIT の恩恵受けてるんだ?
Compiler.codelist• コードキャッシュ内に存在するメソッドを一覧表示
$ jcmd 1234 Compiler.codelist1234:53 4 java.lang.String.hashCode()I [0x00007fd2cd776090, 0x00007fd2cd776200 - 0x00007fd2cd776398]
コンパイルID
コンパイルレベル( Tiered Compilation )
メソッド名nmethod開始アドレス コード開始アドレス
コード終了アドレス
Tiered Compilation を詳しく知りたい方は…• JDK 8 JVM Improvements
• Java Day Tokyo 2014 で David Buck氏が講演• http://
otndnld.oracle.co.jp/ondemand/javaday2014/pdf/C2-JavaDay-304328.pdf
さて、診断ツール仕込むか
JVMTI.agent_load• JVMTI エージェントライブラリのロードを行う
• ネイティブエージェント、 Java エージェントのどちらも可能• エージェントはライブアタッチに対応している必要あり
• ネイティブエージェント: Agent_OnAttach() の実装• Java エージェント: agentmain() の実装
Before• Attach API を使うしかありませんでした…
• 要 Java プログラミング• http://
docs.oracle.com/javase/8/docs/jdk/api/attach/spec/index.html
After• HeapStats をアタッチしてみる
After• HeapStats をアタッチしてみる
0 の意味:Agent_OnAttach() の戻り値http://docs.oracle.com/javase/jp/8/docs/platform/jvmti/jvmti.html#onattach
動かしてみる• JVMTI.data_dump
ヒープの状況をざっくり知りたい
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
jcmd の仕組み
PerfCounter.print• jvmstat Performance Counter を参照する
• /tmp/hsperfdata_<ユーザー名 >/<pid>• バイナリファイルをただパースするだけ
hsperfdata の構造プロローグ(ファイルヘッダ) エントリ
その他のコマンド• 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
詳しくはコチラ• Serviceability Tools の裏側
• http://www.slideshare.net/YaSuenag/serviceability-tools
jcmd の弱点ターゲットプロセスがハングしたら動かない!
※PerfCounter.print 以外
jhsdbServiceability Agent Launcher
jhsdb• Java 9 から新しく入った診断ツール• SA の Launcher
• (CL)HSDB の呼び出しが簡単に!• コア解析、プロセス解析の心強い味方!
SA とは?• Serviceability Agent• 各種ツールの -F オプションやコア解析などで動作するのが SA
• Java 9 からは各種ツールで SA が使えなくなりました!• JDK-8155091: Remove SA related functions from tmtools
• Red Hat系 Linux なら OpenJDK の debuginfo パッケージ必須• ネイティブデバッガ同様の仕組みでプロセスから情報収集
• Linux なら ptrace(2) でプロセスにアタッチ• プロセスハングも関係なし!
http://docs.oracle.com/javase/8/docs/serviceabilityagent/index.html
jhsdb でできることツール名 概要clhsdb コマンドライン版 HotSpot デバッガhsdb GUI 版 HotSpot デバッガjstack SA 版 jstackjmap SA 版 jmapjinfo SA 版 jinfojsnap hsperfdata の読み取り
jhsdb でできないこと• デバッグサーバへの接続はできません
• jsadebugd• HSDB だけは起動後にリモートデバッグサーバに接続できます
• デバッグサーバになることもできません
注意点• オプションは長い名前で指定する
• ex. jstack -m は jhsdb jstack --mixed
• jhsdb jinfo ではフラグ設定はできない• フラグ設定したい場合は jcmd VM.set_flag で
新ツール: jsnap• 実は昔からありました
• sun.jvm.hotspot.tools.JSnap
• hsperfdata の中に入っているパフォーマンスカウンタを読み込む SA• 以下の問題を直して正式デビュー!
• 一部のカウンタしか読み込めない• コアからデータを抜けない
JDK-8151815Could not parse core image with JSnap.
jsnap がなかったら…• コアからカウンタを読み込むのがタイヘン
(gdb) x/g ((G1CollectedHeap *)Universe::_collectedHeap)->_g1mm->_full_collection_counters->_time ->_valuep0x7f8c6884b960: 15535194
例: Full GC の累計実行時間を出してみる( jstat の FGCT相当)
15535194÷1000000000≒0.015 (sec)
GC アルゴリズムによってカウンタへのポインタまでの辿り方違うのかよ…
OpenJDK のソースなんて読みたくねーよ…
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ガンバってます!
クラッシュ解析で困ることHotSpot ( C++ )の世界と
Java の世界を結びつけるのがタイヘン
HSDB
最強デバッガ: HSDB• 実は昔からありました
• sun.jvm.hotspot.HSDB
• HotSpot の世界をわかりやすく解析できるツール• Swing の GUI ツール• コマンドライン版は CLHSDB
• ディスアセンブルもサポート• 要 hsdis
コアを食わせてみる• File
• Open HotSpot core file
クラッシュしたスレッドを見つける• Java Threads
• ゴミ箱アイコン• クラッシュスレッドのスタックメモリを表示• hs_err を吐くようなエラーのみ検知可能
コールスタックを確認してみる• Java Threads
• スレッド選択• 紙(?)アイコン
オブジェクトのメモリを確認する• Tools
• Inspector• oop のアドレスを入力
ディスアセンブルしてみる• Java Stack Trace
• pc をクリック• 要 hsdis
hsdis 利用時に気を付けること
Project Kenai からのダウンロードはやめましょう!
なぜダウンロードはダメなのか?• 古いから
• 一番新しいものでも 6年以上前• 最新の CPU命令をデコードできない
https://kenai.com/projects/base-hsdis/downloads
Project Kenai のもの Fedora23 でビルドしたものStubRoutines::updateBytesCRC32
※OracleJDK 8u92 Linux x64 で確認( -XX:+UnlockDiagnosticVMOptions -XX:+PrintStubCode )
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 本体
hsdis のデプロイ• ~ Java 8
• $JAVA_HOME/jre/lib/amd64• Java 9~
• $JAVA_HOME/lib/amd64
でも、やっぱり最後は…
GDB
怖くない GDB• バックトレースをとるだけでも解析のヒントになる
• クラッシュしたポイントは JNI?• Java Bug System に既知バグがある?
• https://bugs.openjdk.java.net/• debuginfo が入っていれば C/C++ のコードで見れる!
• 必ずしもアセンブラと格闘しなくてよい
Java 9 時代の解析ツール最後にもう 1度
jcmd
jhsdb&
?