在以前的文章中,咱们介绍了JDK14中jstat工具的使用,本文咱们再深刻探讨一下jstack工具的使用。java
jstack工具主要用来打印java堆栈信息,主要是java的class名字,方法名,字节码索引,行数等信息。程序员
更多精彩内容且看:编程
更多内容请访问 www.flydean.com
Usage: jstack [-l][-e] <pid> (to connect to running process) Options: -l long listing. Prints additional information about locks -e extended listing. Prints additional information about threads -? -h --help -help to print this help message
jstack的参数比较简单,l能够包含锁的信息,e包含了额外的信息。c#
咱们举个例子:安全
jstack -l -e 53528
输出结果以下:多线程
2020-05-09 21:46:51 Full thread dump Java HotSpot(TM) 64-Bit Server VM (14.0.1+7 mixed mode, sharing): Threads class SMR info: _java_thread_list=0x00007fda0660eb00, length=14, elements={ 0x00007fda04811000, 0x00007fda05845800, 0x00007fda05012000, 0x00007fda05847800, 0x00007fda05843800, 0x00007fda05854800, 0x00007fda0481f000, 0x00007fda0481f800, 0x00007fda04018800, 0x00007fda041ff800, 0x00007fda05a28800, 0x00007fda05b1a800, 0x00007fda05b1d800, 0x00007fda042be000 } "Reference Handler" #2 daemon prio=10 os_prio=31 cpu=0.67ms elapsed=66335.21s allocated=0B defined_classes=0 tid=0x00007fda04811000 nid=0x4603 waiting on condition [0x000070000afe1000] java.lang.Thread.State: RUNNABLE at java.lang.ref.Reference.waitForReferencePendingList(java.base@14.0.1/Native Method) at java.lang.ref.Reference.processPendingReferences(java.base@14.0.1/Reference.java:241) at java.lang.ref.Reference$ReferenceHandler.run(java.base@14.0.1/Reference.java:213) Locked ownable synchronizers: - None ... "VM Thread" os_prio=31 cpu=1433.78ms elapsed=66335.22s tid=0x00007fda0506b000 nid=0x4803 runnable "GC Thread#0" os_prio=31 cpu=18.63ms elapsed=66335.23s tid=0x00007fda0502a800 nid=0x3203 runnable "GC Thread#1" os_prio=31 cpu=19.64ms elapsed=66334.06s tid=0x00007fda050e5800 nid=0x9d03 runnable "GC Thread#2" os_prio=31 cpu=17.72ms elapsed=66334.06s tid=0x00007fda05015000 nid=0x6203 runnable "GC Thread#3" os_prio=31 cpu=14.57ms elapsed=66332.78s tid=0x00007fda05138800 nid=0x6503 runnable "G1 Main Marker" os_prio=31 cpu=0.25ms elapsed=66335.23s tid=0x00007fda05031000 nid=0x3303 runnable "G1 Conc#0" os_prio=31 cpu=14.85ms elapsed=66335.23s tid=0x00007fda05031800 nid=0x4b03 runnable "G1 Refine#0" os_prio=31 cpu=3.25ms elapsed=66335.23s tid=0x00007fda0583a800 nid=0x4a03 runnable "G1 Young RemSet Sampling" os_prio=31 cpu=5929.79ms elapsed=66335.23s tid=0x00007fda0505a800 nid=0x3503 runnable "VM Periodic Task Thread" os_prio=31 cpu=21862.12ms elapsed=66335.13s tid=0x00007fda0505b000 nid=0xa103 waiting on condition JNI global refs: 43, weak refs: 45
输出的结果咱们能够分为下面几个部分:jvm
JVM虚拟机信息编程语言
第一部分是JVM虚拟机的信息工具
2020-05-09 21:46:51 Full thread dump Java HotSpot(TM) 64-Bit Server VM (14.0.1+7 mixed mode, sharing):
上面显示了虚拟机的thread dump时间和虚拟机的版本等信息。区块链
Threads class SMR info
第二部分是JVM中非JVM(非VM和非GC的线程)的内部线程信息。
Threads class SMR info: _java_thread_list=0x00007fda0660eb00, length=14, elements={ 0x00007fda04811000, 0x00007fda05845800, 0x00007fda05012000, 0x00007fda05847800, 0x00007fda05843800, 0x00007fda05854800, 0x00007fda0481f000, 0x00007fda0481f800, 0x00007fda04018800, 0x00007fda041ff800, 0x00007fda05a28800, 0x00007fda05b1a800, 0x00007fda05b1d800, 0x00007fda042be000 }
这些elements是和后面线程的tid相匹配的。表示的是本地线程对象的地址,注意这些不是线程的ID。
你们可能注意到了里面写的是SMR, SMR全称是Safe Memory Reclamation。
什么是SMR呢?简单点讲就是安全的内存分配,通常这个问题会出如今非自动GC的编程语言中如C++。在这些语言中,须要本身来为对象分配内存和销毁对象,这样就可能致使在多线程的环境中,一个地址可能被分配给了多个对象,从而出现了内存分配的不安全。
线程信息
第三部分就是线程的具体信息了:
"Reference Handler" #2 daemon prio=10 os_prio=31 cpu=0.67ms elapsed=66335.21s allocated=0B defined_classes=0 tid=0x00007fda04811000 nid=0x4603 waiting on condition [0x000070000afe1000] java.lang.Thread.State: RUNNABLE at java.lang.ref.Reference.waitForReferencePendingList(java.base@14.0.1/Native Method) at java.lang.ref.Reference.processPendingReferences(java.base@14.0.1/Reference.java:241) at java.lang.ref.Reference$ReferenceHandler.run(java.base@14.0.1/Reference.java:213) Locked ownable synchronizers: - None
按照字段的顺序,咱们能够把线程信息分为下面几个部分:
注意'allocated=' 和 'defined_classes=' 必需要开启 -XX:+PrintExtendedThreadInfo才会输出数据。
Thread Stack Trace
接下来就是线程的堆栈信息:
java.lang.Thread.State: RUNNABLE at java.lang.ref.Reference.waitForReferencePendingList(java.base@14.0.1/Native Method) at java.lang.ref.Reference.processPendingReferences(java.base@14.0.1/Reference.java:241) at java.lang.ref.Reference$ReferenceHandler.run(java.base@14.0.1/Reference.java:213)
上面的例子是线程的堆栈信息,而且列出来了线程的状态。
Locked Ownable Synchronizer
接下来的部分是该线程拥有的,可用的用于同步的排它锁对象。
Ownable Synchronizer是一个同步器,这个同步器的同步属性是经过使用AbstractOwnableSynchronizer或者它的子类来实现的。
例如ReentrantLock和ReentrantReadWriteLock中的write-lock(注意不是read-lock,由于须要排它性)就是两个例子。
JVM Threads
接下来是JVM的线程信息,由于这个线程是JVM内部的,因此没有线程ID:
"VM Thread" os_prio=31 cpu=1433.78ms elapsed=66335.22s tid=0x00007fda0506b000 nid=0x4803 runnable "GC Thread#0" os_prio=31 cpu=18.63ms elapsed=66335.23s tid=0x00007fda0502a800 nid=0x3203 runnable "GC Thread#1" os_prio=31 cpu=19.64ms elapsed=66334.06s tid=0x00007fda050e5800 nid=0x9d03 runnable "GC Thread#2" os_prio=31 cpu=17.72ms elapsed=66334.06s tid=0x00007fda05015000 nid=0x6203 runnable "GC Thread#3" os_prio=31 cpu=14.57ms elapsed=66332.78s tid=0x00007fda05138800 nid=0x6503 runnable "G1 Main Marker" os_prio=31 cpu=0.25ms elapsed=66335.23s tid=0x00007fda05031000 nid=0x3303 runnable "G1 Conc#0" os_prio=31 cpu=14.85ms elapsed=66335.23s tid=0x00007fda05031800 nid=0x4b03 runnable "G1 Refine#0" os_prio=31 cpu=3.25ms elapsed=66335.23s tid=0x00007fda0583a800 nid=0x4a03 runnable "G1 Young RemSet Sampling" os_prio=31 cpu=5929.79ms elapsed=66335.23s tid=0x00007fda0505a800 nid=0x3503 runnable "VM Periodic Task Thread" os_prio=31 cpu=21862.12ms elapsed=66335.13s tid=0x00007fda0505b000 nid=0xa103 waiting on condition
JNI References
最后一部分是JNI(Java Native Interface)引用的信息,注意这些引用可能会致使内存泄露,由于这些native的引用并不会被自动垃圾回收。
JNI global refs: 43, weak refs: 45
jstack是分析线程的很是强大的工具,但愿你们可以使用起来。
本文做者:flydean程序那些事本文连接:http://www.flydean.com/jdk14-jvm-jstack/
本文来源:flydean的博客
欢迎关注个人公众号:程序那些事,更多精彩等着您!