前言
Stack Trace for Java 显示虚拟机的线程快照
生成虚拟机当前时刻的线程快照(一般是threaddump或者javacore文件),线程快照就是每一条线程正在执行的方法堆栈的集合。
目的
定位线程出现长时间停顿的原因,如线程死锁、死循环等等。
命令格式
jstack [option] vmidoption:-F 正常输出不响应时,强制输出线程堆栈(程序卡死,无法响应时,就需要此参数)-l 额外显示锁的附加信息-m 如果调用到本地方法的话,显示C/C++的堆栈
文件格式
查看的文件就如下所示:
"CommercialStatsThread1" #25 prio=5 os_prio=31 tid=0x00007f98423fa000 nid=0x9f03 waiting on condition [0x000070000f7d3000]java.lang.Thread.State: TIMED_WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x0000000741517b70> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)"BrokerStatsThread1" #24 prio=5 os_prio=31 tid=0x00007f9843c27000 nid=0x5b03 waiting on condition [0x000070000f6d0000]java.lang.Thread.State: TIMED_WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x0000000741477960> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
修饰符
- locked <地址> 目标:使用synchronized申请对象锁成功,监视器的拥有者。
- waiting to lock <地址> 目标:使用synchronized申请对象锁未成功,在迚入区等待。
- waiting on <地址> 目标:使用synchronized申请对象锁成功后,释放锁幵在等待区等待。
- parking to wait for <地址> 目标
使用例子
- jstack pid
- jstack -l 4089 >1.txt
- 查找最消耗CPU的例子
查找最耗时CPU
top命令找出消耗CPU高的Java进程及其线程id:- 开启线程显示模式(
top -H,或是打开top后按H) - 按
CPU使用率排序(top缺省是按CPU使用降序,已经合要求;打开top后按P可以显式指定按CPU使用降序) - 记下
Java进程id及其CPU高的线程id
- 开启线程显示模式(
- 查看消耗
CPU高的线程栈:- 用进程
id作为参数,jstack出有问题的Java进程 - 手动转换线程
id成十六进制(可以用printf %x 1234) - 在
jstack输出中查找十六进制的线程id(可以用vim的查找功能/0x1234,或是grep 0x1234 -A 20)
- 用进程
- 查看对应的线程栈,分析问题
命令操作如下:
1.top查找出哪个进程消耗的cpu高。执行top命令,默认是进程视图,其中PID是进程号co_ad2 18 0 1817m 776m 9712 S 3.3 4.9 12:03.24 javaco_ad 21 0 3028m 2.5g 9432 S 1.0 16.3 6629:44 ja这里我们分析21125这个java进程2.top中shift+h 或“H”查找出哪个线程消耗的cpu高先输入top,然后再按shift+h 或“H”,此时打开的是线程视图,pid为线程号co_ad2 15 0 1807m 630m 9492 S 1.3 4.0 0:05.12 javaco_ad2_s 15 0 1360m 560m 9176 S 0.3 3.6 0:46.72 java这里我们分析21233这个线程,并且注意的是,这个线程是属于21125这个进程的。3.使用jstack命令输出这一时刻的线程栈,保存到文件,命名为jstack.log。注意:输出线程栈和保存top命令快照尽量同时进行。由于jstack.log文件记录的线程ID是16进制,需要将top命令展示的线程号转换为16进制。4. jstack查找这个线程的信息jstack [进程]|grep -A 10 [线程的16进制]即: jstack 21125|grep -A 10 52f1-A 10表示查找到所在行的后10行。21233用计算器转换为16进制52f1,注意字母是小写。结果:"http-8081-11" daemon prio=10 tid=0x00002aab049a1800 nid=0x52bb in Object.wait() [0x0000000042c75000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)at java.lang.Object.wait(Object.java:485)at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:416)在结果中查找52f1,可看到当前线程在做什么。
以上结果查询慢的可以使用github上的脚本快速查看:
show-busy-java-threads
