jhsdb
Jhsdb全称Java Hotspot Debugger,Hotspot进程调试器,可用于从崩溃的JVM附加到Java进程或核心转储。
jhsdb是一款基于Serviceability Agent(可维护性代理,简写为SA)的调试工具。Serviceability Agent是一个JDK组件,用于快照调试、性能分析以及深入了解Hotspot JVM / Hotspot JVM上执行的Java应用程序。
它的工作原理有点类似于Linux上的GDB或者Windows上的Windbg。但尽管诸如gdb的本机调试器可用于检查JVM,但这类本机调试器对Hotspot中的数据结构没有内在了解,因此无法对正在执行的Java应用程序进行深入了解。jhsdb了解JVM关键组件(例如Java堆,堆的代,region,代码缓存等)的位置和地址范围。
参考文档
- Java 8:无,Java 9才正式引入。
- Java 11:https://docs.oracle.com/en/java/javase/11/tools/jhsdb.html
TIPS
尽管JDK 8及更低版本不直接提供jhsdb命令,但依然其实也是可以使用jhsdb的,只需找到 JAVA_HOME/lib 目录下的sa-jdi.jar文件,然后启动即可。步骤如下:
# 修改环境变量JAVA_HOME(这里用export临时修改环境变量,当然也可永久修改)export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home"# 为sa-jdi.jar授予执行权限sudo chmod +x $JAVA_HOME/lib/sa-jdi.jar# 启动方式1:使用交互式命令行调试器(相当于jhsdb clhsdb)java -cp $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.CLHSDB# 启动方式2:使用交互式GUI调试器启动jhsdb(相当于jhsdb hsdb)java -cp $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB
使用说明
# 启动交互式命令行调试器jhsdb clhsdb [--pid pid | --exe executable --core coredump]# 启动远程调试服务器jhsdb debugd [options] (pid | executable coredump) [server-id]# 启动交互式GUI调试器jhsdb hsdb [--pid pid | --exe executable --core coredump]# 打印堆栈并锁定信息jhsdb jstack [--pid pid | --exe executable --core coredump] [options]# 打印堆信息jhsdb jmap [--pid pid | --exe executable --core coredump] [options]# 打印基本的JVM信息jhsdb jinfo [--pid pid | --exe executable --core coredump] [options]# 打印性能计数器信息jhsdb jsnap [options] [--pid pid | --exe executable --core coredump]
其中:
- pid:进程号
- server-id:当多个调试服务器在同一远程主机上运行时使用的可选唯一ID
- executable:从中生成核心转储的Java可执行文件
- coredump:jhsdb工具连接到的Dump文件coredump介绍与开启方式:https://www.cnblogs.com/Anker/p/6079580.html
- options:命令行选项,和子命令有关。
options说明
jhsdb clhsdb子命令
- 无
示例:
# 进入clhsdbjhsdb clhsdb --pid 81033
进入交互界面后,输入help,查看相关的命令,命令如下:
Available commands:assert true | false turn on/off asserts in SA codeattach pid | exec core attach SA to a process or corebuildreplayjars [all | boot | app] build jars for replay, boot.jar for bootclasses, app.jar for application classesclass name find a Java class from debuggee and print oopclasses print all loaded Java classes with Klass*detach detach SA from current targetdis address [ length ] disassemble (sparc/x86) specified number of instructions from given addressdissemble address disassemble nmethoddumpcfg -a | id Dump the PhaseCFG for every compiler thread that has one livedumpclass { address | name } [ directory ] dump .class file for given Klass* or class namedumpcodecache dump codecache contentsdumpheap [ file ] dump heap in hprof binary formatdumpideal -a | id dump ideal graph like debug flag -XX:+PrintIdealdumpilt -a | id dump inline tree for C2 compilationdumpreplaydata| -a | [>replay.txt] dump replay data into a fileecho [ true | false ] turn on/off command echo modeexamine [ address/count ] | [ address,address] show contents of memory from given addressfield [ type [ name fieldtype isStatic offset address ] ] print info about a field of HotSpot typefindpc address print info. about pointer locationflags [ flag ] show all -XX flag name value pairs. or just show given flaghelp [ command ] print help message for all commands or just given commandhistory show command history. usual !command-number syntax works.inspect expression inspect a given oopintConstant [ name [ value ] ] print out hotspot integer constant(s)jdis address show bytecode disassembly of a given Method*jhisto show Java heap histogramjseval script evaluate a given string as JavaScript codejsload file load and evaluate a JavaScript filejstack [-v] show Java stack trace of all Java threads. -v is verbose modelivenmethods show all live nmethodslongConstant [ name [ value ] ] print out hotspot long constant(s)smem address [ length ] show contents of memory -- also shows closest ELF/COFF symbol if foundpmap show Solaris pmap-like outputprint expression print given Klass*, Method* or arbitrary addressprintas type expression print given address as given HotSpot type. eg. print JavaThread <address>printmdo -a | expression print method data oopprintstatics [ type ] print static fields of given HotSpot type (or all types if none specified)pstack [-v] show mixed mode stack trace for all Java, non-Java threads. -v is verbose modequit quit CLHSDB toolreattach detach and re-attach SA to current targetrevptrs find liveness of oopsscanoops start end [ type ] scan a Oop from given start to end addresssearch [ heap | codecache | threads ] value search a value in heap or codecache or threadssource filename load and execute CLHSDB commands from given filesymbol name show address of a given ELF/COFF symbolsysprops show all Java System propertiesthread id show thread of idthreads show all Java threadstokenize ...type [ type [ name super isOop isInteger isUnsigned size ] ] show info. on HotSpot typeuniverse print gc universevmstructsdump dump hotspot type library in textverbose true | false turn on/off verbose modeversioncheck [ true | false ] turn on/off debuggee VM version checkwhatis address print info about any arbitrary addresswhere { -a | id } print Java stack trace of given Java thread or all Java threads (-a)
TIPS
不同版本支持的命令可能不同,这里列出的命令可能你的JVM并不一定能支持。
参考文档:
- http://cr.openjdk.java.net/~minqi/6830717/raw_files/new/agent/doc/clhsdb.html
https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/jdk.hotspot.agent/doc/clhsdb.html
jhsdb hsdb子命令
无
示例:
# 图形化模式,和clhsdb功能对标jhsdb hsdb --pid 81033
jhsdb jinfo子命令
- –flags:打印VM标志
- –sysprops:打印Java系统属性
- 留空:打印VM标志和Java系统属性
示例:
# 打印80904进程的VM标志jhsdb jinfo --flags --pid 80904# 打印80904进程的系统属性jhsdb jinfo --sysprops --pid 80904
jhsdb jmap子命令
- –heap:打印Java堆的概要信息
- –binaryheap:将Java堆以hprof格式Dump出来
- –dumpfile:执行dump文件名
- –histo:打印Java堆的直方图
- –clstats:打印Java堆的类加载器统计信息
- –finalizerinfo:打印等待finalization的对象的信息
示例:
# 打印81033进程Java堆的直方图jhsdb jmap --histo --pid 81033# 将81033进程的Java堆dump到2.hprofjmap --binaryheap --dumpfile 2.hprof --pid 81033
jhsdb jstack子命令
- –locks:打印java.util.concurrent锁的信息
- –mixed:尝试打印Java栈与本地方法栈的信息(需操作系统支持)
示例:
# 打印81033锁的信息,并尝试打印Java栈与本地方法栈的信息jhsdb jstack --locks --mixed --pid 81033
jhsdb jsnap子命令
- –all:打印所有性能计数器的信息
示例:
jhsdb jsnap --all --pid 81033
相当于:
jcmd 81033 PerfCounter.print
jhsdb debugd子命令
- server-id:当多个调试服务器在同一远程主机上运行时使用的可选唯一ID
示例:
jhsdb debugd 81033
TIPS
debugd子命令的格式和其他子命令不同,这是个bug,在JDK 13中已经和其他子命令保持一致了。
https://bugs.openjdk.java.net/browse/JDK-8223666
jhsdb和其他工具的对比
| 功能 | JHSDB | JCMD | 类似工具 |
|---|---|---|---|
| 展示Java进程 | N/A | jcmd | jps -lm |
| 堆Dump | jhsdb jmap —binaryheap | jcmd pid GC.heap_dump | jmap -dump pid |
| 堆使用直方图 | jhsdb jmap —histo | jcmd pid GC.class_histogram | jmap -histo pid |
| 线程Dump | jhsdb jstack —locks (subset of locked thread frames) | jcmd pid Thread.print | jstack pid |
| 展示系统属性 | jhsdb jinfo —sysprops | jcmd pid VM.system_properties | jinfo -sysprops pid |
| 列出VM标记 | jhsdb jinfo —flags | jcmd pid VM.flags | jinfo -flags pid |
macOS下遇到的问题
在macOS下,目前最新的11.0.7中的jhsdb无法正常使用,会报类似如下异常:
Error attaching to process: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 11.0.7+8-LTS. Target VM is 11.0.4+10-LTSsun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 11.0.7+8-LTS. Target VM is 11.0.4+10-LTSat jdk.hotspot.agent/sun.jvm.hotspot.HotSpotAgent.setupVM(HotSpotAgent.java:436)at jdk.hotspot.agent/sun.jvm.hotspot.HotSpotAgent.go(HotSpotAgent.java:306)at jdk.hotspot.agent/sun.jvm.hotspot.HotSpotAgent.attach(HotSpotAgent.java:141)at jdk.hotspot.agent/sun.jvm.hotspot.tools.Tool.start(Tool.java:185)at jdk.hotspot.agent/sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)at jdk.hotspot.agent/sun.jvm.hotspot.tools.JStack.runWithArgs(JStack.java:90)at jdk.hotspot.agent/sun.jvm.hotspot.SALauncher.runJSTACK(SALauncher.java:259)at jdk.hotspot.agent/sun.jvm.hotspot.SALauncher.main(SALauncher.java:450)
这是JDK版本的问题(JDK bug,只在macOS下出现),只需将JDK降级至11.0.4即可,也可在Linux或Windows下测试jhsdb工具。
JDK 11.0.4下载地址:
- https://www.oracle.com/java/technologies/javase/jdk11-archive-downloads.html
- 百度加速下载:链接:https://pan.baidu.com/s/1HXjzNDpzin6fXGrZPyQeWQ 密码:aon2 1 代码块
安装完成后,先用JDK 11.0.4启动一个应用,然后即可使用jhsdb工具调试该应用了。
