原来jdk自带了这么好玩的工具 —— 使用 jstack定位死循环

  • prio:线程优先级

  • tid:指Java Thread id。

  • nid:指native线程的id。。

  • [0x00007000085aa000]:线程栈起始地址。

-l打印锁的附加信息


这里我们使用2个窗口,分别使用以下2个命令来测试

第一个窗口执行

jstack -l 12771

第二个窗口中执行

jstack 12771

通过2个窗口对比可以看到,加了-l的命令多打印了锁的信息;

v2-19ddd5f405efde8494cc437f29efe59f_b.jpg

导出堆栈文件


一般情况下,如果程序出错了, 都不会直接在生产环境的服务器上找错误,这个时候就可以用到一个非常实用的功能,将堆栈快照导出来,然后copy到别的电脑上看,命令如下

jstack -l 2289 > jstackDump.txt

执行后,就可以看到文件已经导出来了

v2-94841bc762a229948d6468dd34276fda_b.jpg

通过cat命令可以看到,里面的内容和我们在命令行输出的内容是一样的

v2-14294e8b8ea54b9387433dd639671b2e_b.jpg

实战一 、 找出cpu占用最高的线程(linux系统)


首先我们准备好一个死循环的线程,在线程内定一个while的死循环,并且给这个线程起个名字为:yexindogn,阿里巴巴的开发规范里面有一个规定,就是每个线程必须起一个名字,起名字就是为了 以后程序出问题的时候好找错误;

public static void main(String[] args) throws InterruptedException {

new Thread(new Runnable() {

@Override

public void run() {

while(true){

System.out.println(112);

}

}

},“yexindong”).start();

System.out.println(“我执行了”);

}

接着我们将此代码打成jar包扔到linux服务器上运行,直接输入 java -jar Test.jar 命令即可运行,运行后我们可以看到控制台一直在输出112这个字符,这就代表程序已经在运行了;

v2-82a73d3845552e435295ac7a9b700987_b.jpg

接着在看下CPU的运行情况,使用top命令查看cpu占用情况,排在第一位的是进程号为30328的进程,占用了6.6%的cpu; 这边我使用了2个命令行连到同一台服务器,一个窗口用来运行刚刚的jar包,另一个窗口用来查找错误;

v2-abf51dc91438bd7bb2d79cc453579849_b.jpg

找线程 - 第一种方式


知道进程号了,接着就是找线程了,输入以下命令

top -Hp 30328

打印结果如下,这里有一点需要注意,在我们加上-Hp指令后,PID展示就是线程的id了,这时候我们看到占用CPU最高的线程id是30365;

v2-85128cf6238da200ce20dfcfb31535d9_b.jpg

找线程 - 第二种方式


还有另一种方式,就是使用ps命令来查找线程

ps -mp 30328 -o THREAD,tid,time| sort -n -k1 -r

通过这个命令我们可以看到这边占用最高的线程id也是30365 ;

v2-cbb61dde955ed10c1f55c5716798996d_b.jpg

以上的方式我们成功找到了占用cpu高的线程id是30365,但这个id是十进制的,在这里需要先转为16进制,输入命令

printf “%x\n” 30365

计算出对应的16进制为:769d

v2-e069cb2ce3ac13417c178c83eee4aaa6_b.jpg

当然也可以用其他的计算工具,比如mac系统自带计算器就支持进制之间的转换

v2-91a227e55be7dbe20f573c2e03eebf12_b.jpg

使用jstack分析堆栈快照


1、快速查找 (推荐使用)


在命令行输入以下命令,这种方法更加快速,推荐使用

jstack 12771 | grep -A 20 ‘769d’

其中,grep 命令是查找结果为769d的内容,-A 20 表示打印匹配所在行的后20行内容。直接帮我们定位到所在线程的堆栈,结果如下

“yexindong” #8 prio=5 os_prio=0 tid=0x00007effd0182000 nid=0x769d runnable [0x00007effbea0f000]

java.lang.Thread.State: RUNNABLE

at java.io.FileOutputStream.writeBytes(Native Method)

at java.io.FileOutputStream.write(FileOutputStream.java:326)

at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)

at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)

  • locked <0x00000000ecd6ea10> (a java.io.BufferedOutputStream)

at java.io.PrintStream.write(PrintStream.java:482)

  • locked <0x00000000ecd65a10> (a java.io.PrintStream)

at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)

at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)

at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)

  • locked <0x00000000ecd659c8> (a java.io.OutputStreamWriter)

at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)

at java.io.PrintStream.newLine(PrintStream.java:546)

  • locked <0x00000000ecd65a10> (a java.io.PrintStream)

at java.io.PrintStream.println(PrintStream.java:737)

  • locked <0x00000000ecd65a10> (a java.io.PrintStream)

at com.test.Test$1.run(Test.java:13)

at java.lang.Thread.run(Thread.java:748)

2、常规方法


当然也可以用下面的死办法,先打印出所有的堆栈快照;

jstack 30328

打印结果如下

[root@VM_0_5_centos ~]# jstack 30328

2021-07-14 23:40:34

Full thread dump OpenJDK 64-Bit Server VM (25.232-b09 mixed mode):

“Attach Listener” #10 daemon prio=9 os_prio=0 tid=0x00007effa4001000 nid=0x12f9 waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

“DestroyJavaVM” #9 prio=5 os_prio=0 tid=0x00007effd004b800 nid=0x7679 waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

“yexindong” #8 prio=5 os_prio=0 tid=0x00007effd0182000 nid=0x769d runnable [0x00007effbea0f000]

java.lang.Thread.State: RUNNABLE

at java.io.FileOutputStream.writeBytes(Native Method)

at java.io.FileOutputStream.write(FileOutputStream.java:326)

at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)

at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)

  • locked <0x00000000ecd6ea10> (a java.io.BufferedOutputStream)

at java.io.PrintStream.write(PrintStream.java:482)

  • locked <0x00000000ecd65a10> (a java.io.PrintStream)

at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)

at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)

at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)

  • locked <0x00000000ecd659c8> (a java.io.OutputStreamWriter)

at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)

at java.io.PrintStream.newLine(PrintStream.java:546)

  • locked <0x00000000ecd65a10> (a java.io.PrintStream)

at java.io.PrintStream.println(PrintStream.java:737)

  • locked <0x00000000ecd65a10> (a java.io.PrintStream)

at com.test.Test$1.run(Test.java:13)

at java.lang.Thread.run(Thread.java:748)

“Service Thread” #7 daemon prio=9 os_prio=0 tid=0x00007effd013e800 nid=0x769b runnable [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

“C1 CompilerThread1” #6 daemon prio=9 os_prio=0 tid=0x00007effd013b800 nid=0x769a waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

“C2 CompilerThread0” #5 daemon prio=9 os_prio=0 tid=0x00007effd012d000 nid=0x768b waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

“Signal Dispatcher” #4 daemon prio=9 os_prio=0 tid=0x00007effd012a800 nid=0x7689 runnable [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

“Finalizer” #3 daemon prio=8 os_prio=0 tid=0x00007effd0101000

【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】

浏览器打开:qq.cn.hn/FTf 免费领取

nid=0x7683 in Object.wait() [0x00007effbf906000]

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

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

  • waiting on <0x00000000ecd66260> (a java.lang.ref.ReferenceQueue$Lock)

at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)

  • locked <0x00000000ecd66260> (a java.lang.ref.ReferenceQueue$Lock)

at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)

at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

“Reference Handler” #2 daemon prio=10 os_prio=0 tid=0x00007effd00fc000 nid=0x767f in Object.wait() [0x00007effbfa07000]

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

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

  • waiting on <0x00000000ecd66418> (a java.lang.ref.Reference$Lock)

at java.lang.Object.wait(Object.java:502)

at java.lang.ref.Reference.tryHandlePending(Reference.java:191)

  • locked <0x00000000ecd66418> (a java.lang.ref.Reference$Lock)

at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

“VM Thread” os_prio=0 tid=0x00007effd00f2800 nid=0x767d runnable

“VM Periodic Task Thread” os_prio=0 tid=0x00007effd0141000 nid=0x769c waiting on condition

JNI global references: 5

接着我用刚刚计算出来的16进制复制出来在这里搜索一下,经过查看就知道是我们刚刚起了名字为yexindong的线程出错了,出错的位置在Test.java的第13行代码

v2-9e18ca759bbf270490661e55ec382c3d_b.jpg

我们看看java代码,确实是第13行这里的死循环导致的

v2-0e73a8bd6c1237e37298ed739767db71_b.jpg

实战二、 找出cpu占用最高的线程(windows系统)


首先打开任务管理器,因为默认windows的任务管理器是不显示进程pid的,所以我们需要设置一下,选择 查看 → 选择列(S)…

v2-b32bc903d9ba8844bf49a10133286bc4_b.jpg

选中PID进程表示符后点击确定按钮

v2-4976ce25f87894e45de3981bfce8a201_b.jpg

查进程号pid


然后我们就可以看到占用CPU最高的java进程PID为:976

v2-e0aa569d762ded11d8cfa21757ad6d62_b.jpg

查线程号TID


因为windows不能直接查看java进程中的线程信息,所以我们需要借助一个工具,这个工具是微软自己开发的,叫做Process Explorer ,网上很多,需要的童鞋请自行百度,打开后找到pid为976的进程右击选择 → 属性

a代码,确实是第13行这里的死循环导致的

[外链图片转存中…(img-i49cABgF-1635766281876)]

实战二、 找出cpu占用最高的线程(windows系统)


首先打开任务管理器,因为默认windows的任务管理器是不显示进程pid的,所以我们需要设置一下,选择 查看 → 选择列(S)…

[外链图片转存中…(img-8v5n8LNu-1635766281877)]

选中PID进程表示符后点击确定按钮

[外链图片转存中…(img-7lXB3BjO-1635766281878)]

查进程号pid


然后我们就可以看到占用CPU最高的java进程PID为:976

[外链图片转存中…(img-PLDr2vVj-1635766281879)]

查线程号TID


因为windows不能直接查看java进程中的线程信息,所以我们需要借助一个工具,这个工具是微软自己开发的,叫做Process Explorer ,网上很多,需要的童鞋请自行百度,打开后找到pid为976的进程右击选择 → 属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值