The jstack command prints Java stack traces of Java threads for a specified Java process
用法: jstack [-l][-e]
选项:
-l
: long listing. Prints additional information about locks-e
: extended listing. Prints additional information about threads下面的Java代码:
package pkg1;
public class Test0608 {
public static void main(String[] args) {
Thread.currentThread().setName("MyThread1");
int i = 0;
while(true) {
i++;
i--;
i++;
i--;
if (i > 100)
i = 0;
}
}
}
这是一个死循环的程序。
注: Test0608.java
文件位于 pkg1
目录下。当前位于 pkg1
目录下。
javac pkg1/Test0608.java
java pkg1.Test0608
(可以加上 -cp .
)运行程序后,陷入死循环,CPU占用率就会飙升。
使用 top
命令查看进程(按下 P
键,按CPU排序,按下 M
键,则按内存排序)
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
27139 ding 20 0 4825108 31552 24268 S 100.3 0.4 0:14.44 java
1916 ding 20 0 4412772 283628 131928 S 1.3 3.5 1:30.23 gnome-shell
1179 mysql 20 0 2374480 395512 35136 S 0.3 4.9 4:03.78 mysqld
可见,进程 27139
的CPU使用率最高,达到了100%。
可以使用 ps
查看该进程:
ps -ef | grep 27139
ding 27139 3096 99 20:42 pts/0 00:01:06 java pkg1.Test0608
ding 27189 26323 0 20:43 pts/1 00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox 27139
如果是Java进程,也可以使用 jps
命令来查看:
jps
27200 Jps
27139 Test0608
定位到进程号以后,接下来用 top -H -p
来查看其线程:
top -H -p 27139
top - 20:44:14 up 6:16, 1 user, load average: 1.23, 0.63, 0.47
Threads: 19 total, 1 running, 18 sleeping, 0 stopped, 0 zombie
%Cpu(s): 12.6 us, 0.2 sy, 0.0 ni, 87.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7914.8 total, 1831.0 free, 2691.5 used, 3392.3 buff/cache
MiB Swap: 2048.0 total, 2045.0 free, 3.0 used. 4896.5 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
27140 ding 20 0 4825108 31552 24268 R 99.7 0.4 2:11.07 MyThread1
27139 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 java
27141 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 GC Thread#0
27142 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 G1 Main Marker
27143 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 G1 Conc#0
27144 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 G1 Refine#0
27145 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.01 G1 Service
27146 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 VM Thread
27147 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Reference Handl
27148 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Finalizer
27149 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Signal Dispatch
27150 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Service Thread
27151 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Monitor Deflati
27152 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 C2 CompilerThre
27153 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 C1 CompilerThre
27154 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Sweeper thread
27155 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Notification Th
27156 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.07 VM Periodic Tas
27157 ding 20 0 4825108 31552 24268 S 0.0 0.4 0:00.00 Common-Cleaner
可见,线程 27140
占用了100%的CPU。其线程名为 MyThread1
(所运行Java程序的主线程)。
获取 27140
的16进制值:
printf "0x%x\n" 27140
0x6a04
这是为了接下来方便查找。
现在,已经知道了CPU占用率高的进程和线程,终于轮到jstack出场了。
jstack -l 27139
2023-06-08 20:44:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (17.0.3.1+2-LTS-6 mixed mode, sharing):
Threads class SMR info:
_java_thread_list=0x00007f3e98002010, length=12, elements={
0x00007f3ee0023bb0, 0x00007f3ee0139080, 0x00007f3ee013a460, 0x00007f3ee01406a0,
0x00007f3ee0141a50, 0x00007f3ee0142e60, 0x00007f3ee0144810, 0x00007f3ee0145d40,
0x00007f3ee014f1a0, 0x00007f3ee01568d0, 0x00007f3ee0159fd0, 0x00007f3e98001090
}
"MyThread1" #1 prio=5 os_prio=0 cpu=169036.84ms elapsed=169.11s tid=0x00007f3ee0023bb0 nid=0x6a04 runnable [0x00007f3ee5dfd000]
java.lang.Thread.State: RUNNABLE
at pkg1.Test0608.main(Test0608.java:12)
Locked ownable synchronizers:
- None
"Reference Handler" #2 daemon prio=10 os_prio=0 cpu=0.15ms elapsed=169.10s tid=0x00007f3ee0139080 nid=0x6a0b waiting on condition [0x00007f3ec47fe000]
java.lang.Thread.State: RUNNABLE
at java.lang.ref.Reference.waitForReferencePendingList(java.base@17.0.3.1/Native Method)
at java.lang.ref.Reference.processPendingReferences(java.base@17.0.3.1/Reference.java:253)
at java.lang.ref.Reference$ReferenceHandler.run(java.base@17.0.3.1/Reference.java:215)
Locked ownable synchronizers:
- None
......
下面还有很长。为了方便,我们可以用线程名 MyThread1
或者线程号 0x6a04
来查找。最终找到这一段:
"MyThread1" #1 prio=5 os_prio=0 cpu=169036.84ms elapsed=169.11s tid=0x00007f3ee0023bb0 nid=0x6a04 runnable [0x00007f3ee5dfd000]
java.lang.Thread.State: RUNNABLE
at pkg1.Test0608.main(Test0608.java:12)
Locked ownable synchronizers:
- None
这是当前线程状态,可见信息很齐全,有包名,类名,方法名,当前运行的代码行(本例中是第12行)。
可以多运行几次 jstack
命令,如果当前运行的代码行都相同,则这块的代码很可能有问题。对于本例,检查代码第12行,就会很容易发现这里有一个死循环。
https://www.oracle.com/java/technologies/javase/jstack.html
https://blog.csdn.net/u014163312/article/details/124248558