JVM调优—jstack用法

本文介绍如何使用jstack工具生成JVM线程快照,以定位线程间死锁、死循环等问题。通过具体实例展示了从查找进程号、分析CPU占用高的线程到最终确定死锁原因的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jstack可用于生成JVM当前的线程快照,可快速定位线程间死锁、死循环或者线程长时间等待停顿的原因。

jstack命令格式

jstack [option] LVMID 

option参数

-F : 当正常输出请求不被响应时,强制输出线程堆栈

-l : 除堆栈外,显示关于锁的附加信息

-m : 如果调用到本地方法的话,可以显示C/C++的堆栈


Linux下jstack用法

(一)找到进程号:90464

使用命令ps -ef | grep tomcat


(二)找出该进程的占用CPU的线程情况

可以看出占用CPU最高的线程号是90485

使用命令:top -Hp 90464


(三)将90485转换为16进制:16175

使用命令printf "%x\n" 90485


(四)使用jstack命令查看该线程的堆栈信息

使用命令:jstack 90464 | grep 16175

 

(五)Jstack检查死锁的例子

首先看一个java实例

package com.lixin.learning.thread;

 

publicclassTestDeadThreadimplementsRunnable{

 

     publicstaticObjecto1=newObject();

     publicstaticObjecto2=newObject();

     privatebooleanflag;

 

     publicTestDeadThread(booleanflag){

         this.flag=flag;

     }

 

     @Override

     publicvoidrun(){

         StringthreadName=Thread.currentThread().getName();

         if(flag){

              while(true){

                   synchronized(o1){

                       try{

                            Thread.sleep(1000);

                       }catch(InterruptedExceptione){

                            e.printStackTrace();

                       }

                       System.out.println(threadName+"get o1 lock");

                       synchronized(o2){

                            System.out.println(threadName+"get o2 lock");

                       }

                   }

              }

         }else{

              while(true){

                   synchronized(o2){

                       try{

                            Thread.sleep(1000);

                       }catch(InterruptedExceptione){

                            e.printStackTrace();

                       }

                       System.out.println(threadName+"get o2 lock");

                       synchronized(o1){

                            System.out.println(threadName+"get o1 lock");

                       }

                   }

              }

         }

 

     }

 

     publicstaticvoidmain(String[]args){

         TestDeadThreadthreada=newTestDeadThread(true);

         TestDeadThreadthreadb=newTestDeadThread(false);

 

         Threada=newThread(threada);

         Threadb=newThread(threadb);

 

         a.start();

         b.start();

     }

 

}


 输出结果:

Thread-0get o1 lock

Thread-1get o2 lock

1:线程1首先获取对象1的锁,然后睡眠1秒钟

2:线程2获取对象2的锁,也睡眠1秒钟

3:线程1睡眠时间到,想要获取对象2的锁,但是对象2的锁已经被线程2持有,则等待对象2解锁。

4:线程2睡眠时间,想要获取对象1的锁,但是对象1的锁已经被线程1持有,则等待对象1解锁。

这样线程1和线程2相互等待,进入死锁状态。 

 

先通过jpsJVM Process Status)获取进程号

C:\Program  Files\Java\jdk1.8.0_77\bin>jps -l

10736

7808  com.lixin.learning.thread.TestDeadThread

5960 sun.tools.jps.Jps

使用jstack生成java虚拟机当前时刻的线程快照

C:\Program  Files\Java\jdk1.8.0_77\bin>jstack -l 7808 > e:/a.jstack


2017-03-14 10:12:19

Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.77-b03  mixed mode):

 

"DestroyJavaVM" #12 prio=5 os_prio=0  tid=0x00000000024ce800 nid=0x1ac8 waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

 

Locked ownable synchronizers:

- None

 

"Thread-1" #11 prio=5 os_prio=0  tid=0x0000000058b4b000 nid=0x26c8 waiting for monitor entry  [0x0000000059bce000]

java.lang.Thread.State: BLOCKED (on object monitor)

at  com.lixin.learning.thread.TestDeadThread.run(TestDeadThread.java:39)

- waiting to lock <0x00000000d5cf2640> (a  java.lang.Object)

- locked <0x00000000d5cf2650> (a java.lang.Object)

at java.lang.Thread.run(Unknown Source)

 

Locked ownable synchronizers:

- None

 

"Thread-0" #10 prio=5 os_prio=0  tid=0x0000000058b48800 nid=0x2018 waiting for monitor entry  [0x00000000599ce000]

java.lang.Thread.State: BLOCKED (on object monitor)

at  com.lixin.learning.thread.TestDeadThread.run(TestDeadThread.java:25)

- waiting to lock <0x00000000d5cf2650> (a  java.lang.Object)

- locked <0x00000000d5cf2640> (a java.lang.Object)

at java.lang.Thread.run(Unknown Source)

 

Locked ownable synchronizers:

- None

 

"Service Thread" #9 daemon prio=9 os_prio=0  tid=0x0000000058ae7800 nid=0x310c runnable [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

 

Locked ownable synchronizers:

- None

 

"C1 CompilerThread2" #8 daemon prio=9 os_prio=2  tid=0x0000000058a75000 nid=0x1cb0 waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

 

Locked ownable synchronizers:

- None

 

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2  tid=0x0000000058a6c000 nid=0x2388 waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

 

Locked ownable synchronizers:

- None

 

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x0000000058a6b000  nid=0xb1c waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

 

Locked ownable synchronizers:

- None

 

"Attach Listener" #5 daemon prio=5 os_prio=2  tid=0x0000000058a6a000 nid=0x30fc waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

 

Locked ownable synchronizers:

- None

 

"Signal Dispatcher" #4 daemon prio=9 os_prio=2  tid=0x0000000058a67800 nid=0x2e6c runnable [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

 

Locked ownable synchronizers:

- None

 

"Finalizer" #3 daemon prio=8 os_prio=1  tid=0x000000005758b800 nid=0x309c in Object.wait() [0x0000000058a4f000]

java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)

- waiting on <0x00000000d5c08ee0> (a  java.lang.ref.ReferenceQueue$Lock)

at java.lang.ref.ReferenceQueue.remove(Unknown Source)

- locked <0x00000000d5c08ee0> (a  java.lang.ref.ReferenceQueue$Lock)

at java.lang.ref.ReferenceQueue.remove(Unknown Source)

at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)

 

Locked ownable synchronizers:

- None

 

"Reference Handler" #2 daemon prio=10 os_prio=2  tid=0x0000000057544800 nid=0x2708 in Object.wait() [0x00000000588cf000]

java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)

- waiting on <0x00000000d5c06b50> (a  java.lang.ref.Reference$Lock)

at java.lang.Object.wait(Unknown Source)

at java.lang.ref.Reference.tryHandlePending(Unknown Source)

- locked <0x00000000d5c06b50> (a  java.lang.ref.Reference$Lock)

at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)

 

Locked ownable synchronizers:

- None

 

"VM Thread" os_prio=2 tid=0x000000005753c800  nid=0x1ad4 runnable

 

"GC task thread#0 (ParallelGC)" os_prio=0  tid=0x000000000263f000 nid=0x28bc runnable

 

"GC task thread#1 (ParallelGC)" os_prio=0  tid=0x0000000002640800 nid=0x2b04 runnable

 

"GC task thread#2 (ParallelGC)" os_prio=0  tid=0x0000000002642000 nid=0x22a0 runnable

 

"GC task thread#3 (ParallelGC)" os_prio=0  tid=0x0000000002645800 nid=0x215c runnable

 

"VM Periodic Task Thread" os_prio=2  tid=0x0000000058b26800 nid=0x2e7c waiting on condition

 

JNI global references: 6

 

 

Found one Java-level deadlock:

=============================

"Thread-1":

waiting to lock monitor 0x000000005754b148 (object  0x00000000d5cf2640, a java.lang.Object),

which is held by "Thread-0"

"Thread-0":

waiting to lock monitor 0x0000000057548cd8 (object  0x00000000d5cf2650, a java.lang.Object),

which is held by "Thread-1"

 

Java stack information for the threads listed above:

===================================================

"Thread-1":

at  com.lixin.learning.thread.TestDeadThread.run(TestDeadThread.java:39)

- waiting to lock <0x00000000d5cf2640> (a  java.lang.Object)

- locked <0x00000000d5cf2650> (a java.lang.Object)

at java.lang.Thread.run(Unknown Source)

"Thread-0":

at  com.lixin.learning.thread.TestDeadThread.run(TestDeadThread.java:25)

- waiting to lock <0x00000000d5cf2650> (a java.lang.Object)

- locked <0x00000000d5cf2640> (a java.lang.Object)

at java.lang.Thread.run(Unknown Source)

 

Found 1 deadlock.

 

 可以看到jstack检查到了一个线程间死锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cfpl12011124

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值