jstack定位CPU占用率高的线程代码

目录

  • 一、背景
  • 二、jstack定位实战演示
  • 三、关于线程的状态
  • 四、最后

一、背景

性能测试过程中,如果我们发现应用服务器CPU使用率高(超过70%),接口TPS低的现象,此时常见的情况是由以下的原因造成:

  • 复杂的算法导致CPU使用率高,比如加解密算法、序列化等操作;
  • 代码中存在死循环;
  • 大量的logback日志异步写日志消耗cpu;
  • 频繁的fullGC;

这个时候为了进一步定位具体是哪段代码导致CPU使用率高,我们就需要用到jstack命令。整体步骤是:定位CPU占用率高的进程》定位该进程下CPU占用率高的线程》查看该线程堆栈信息日志》定位具体是哪个java类的哪一行代码造成。

二、jstack定位实战演示

1、首先在我的linux虚拟机上先运行一个jmeter,持续长时间运行。
jstack定位CPU占用率高的线程代码_第1张图片

2、使用top命令,查看系统中进程CPU使用率,按一下大写的P键,让进程按照使用率从上往下排序显示:
jstack定位CPU占用率高的线程代码_第2张图片
可以看到PID为4724的java进程占用CPU使用率最多,其实这个进程就是我们jmeter的进程。

3、这个时候有两种做法:
第一种:继续查看进程下到底哪些线程占用CPU高:top -H -p 4724
jstack定位CPU占用率高的线程代码_第3张图片
可以看到PID为4733和4739的线程CPU使用率高。

如果是java应用程序,想获得更多的线程相关信息,需要将上面的进程Id转换成16进制的,因为在java堆栈里,存储线程的Id采用的是16进制,可以直接命令printf %x 4739,输出:1283
在这里插入图片描述
使用jstack命令打印指定线程的运行日志信息:jstack 4739 | grep -C10 1283 --color
4739是进程号,1283是线程的16进制ID,-C10是指显示关键字所在行和前后10行,–color是指带颜色显示关键字1283。
在这里插入图片描述
jstack定位CPU占用率高的线程代码_第4张图片

第二种:直接使用命令 jstack 4724 > 1.txt, 表示直接把进程4724下所有线程运行日志信息,存储到文件 1.txt中, 即我们常说的thread dump文件。
在这里插入图片描述
查看1.txt的内容:
jstack定位CPU占用率高的线程代码_第5张图片

三、关于线程的状态

一般定义一个线程,有6种状态:

  • new: 代表新建状态;
  • RUNNABLE 运行状态,就绪(ready)和运行中(running)两种状态笼统的称为“运行”;
  • BLOCKED 阻塞状态,线程阻塞于锁;
  • WAITING 等待状态,进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断);
  • TIMED_WAITING 超时等待状态,该状态不同于WAITING,它可以在指定的时间后自行返回;
  • TERMINATED 终止状态,表示该线程已经执行完毕。

但是在线程堆栈日志dump文件中,堆栈中的状态和上面线程定义的状态会不太一样。
thread dump 文件下,有以下的线程状态,通常需要重点关注的状态已标粗,这些状态的线程通常是最耗cpu的线程,重点关注这些线程并定位代码:

  • 死锁,Deadlock(死锁,重点关注)
  • 执行中,Runnable
  • 等待资源,Waiting on condition(等待资源,可能线程已经出现排队现象了,重点关注)
  • 等待获取监视器,Waiting on monitor entry(重点关注)
  • 暂停,Suspended
  • 对象等待中,Object.wait() 或 TIMED_WAITING
  • 阻塞,Blocked(重点关注,阻塞状态)
  • 停止,Parked

含义如下所示:

  • Deadlock:死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。
  • Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换。
  • Waiting on condition:等待资源,或等待某个条件的发生。如果堆栈信息明确是应用代码,则证明该线程正在等待资源。一般是大量读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取。又或者,正在等待其他线程的执行等。如果发现有大量的线程都在处在Wait on condition,从线程stack看,正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
  • Blocked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。
  • Waiting for monitor entry:意味着线程在等待进入一个临界区。Monitor是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个monitor。这种状态通常发生在线程在等待数据库连接池返回一个可用的连接。

四、最后

当程序出现故障,往往一次 dump 的信息,还不足以确认问题。建议最好多生成几次 dump 信息,比如3次,如果每次 dump 都指向同一个线程代码,我们才确定问题的典型性。以上,就是如何使用jstack命令查看CPU使用率高的线程运行日志信息,定位到具体的代码行。

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

以上就是本次的全部内容,如果对你有帮助,欢迎关注我的微信公众号:程序员杨叔,各类文章都会第一时间在上面发布,持续分享全栈测试知识干货,你的支持就是作者更新最大的动力~
jstack定位CPU占用率高的线程代码_第6张图片

你可能感兴趣的:(性能测试,软件测试,压力测试,java)