前言
在互联网行业中,高并发的业务为常态,作为一名Java高级工程师,线上问题的排查手段和技巧必须熟练,比如某电商团队的某个应用突然CPU超高,导致报警短信和邮件满天飞,如果让你来定位一个问题,并快速消除预警,你该怎么办?其中一点就是如何定位CPU消耗过高的线程,以及如何找到线程正在干的事情。帮助我们快速的定位问题和分析问题。
本文为日常工作中实战性较强的一个问题分析和定位技能。阅读完本文,你将拥有更高层次的问题分析和处理能力。
如何定位CPU高的线程
大体过程如下:
1、用top -H -p <pid>命令找到CPU高的线程ID。
2、用jstack <vmid>命令打印jvm线程堆栈信息。
3、将第1步拿到的线程ID转换为16进制。(可以用命令 printf '%x\n' ID来输出16进制)
4、用转换后的线程ID在线程堆栈信息中查找匹配的nid线程。
5、到此已经找到线程,以及线程栈的详细信息。可以根据这些信息来判断应用当前正在干什么坏事了。
定位Java线程CPU消耗高的线程(top -H命令)
命令:pid为jvm进程号
top -H -p <pid>
作用:列出指定进程下线程的信息,会按CPU的使用占比从大到小排列。
上图中列分别代表的意思为:进程中的线程ID、用户名、线程优先级
列名 | 含义 |
---|---|
PID | 进程ID |
USER | linux用户名 |
PR | 线程优先级 |
NI | nice值。负值表示高优先级,正值表示低优先级 |
VIRT | 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES |
RES | 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA |
SHR | 共享内存大小,单位kb |
S | 进程状态。 |
%CPU | 上次更新到现在的CPU时间占用百分比 |
%MEM | 进程使用的物理内存百分比 |
TIME+ | 进程使用的CPU时间总计,格式:时:分:秒 |
COMMAND | 命令名/命令行 |
上面的几个参数中,最关心的是PID、USER、%CPU信息。从上图中可以看到CPU占比最高的排在第1位,线程ID位14153(十六进制为:3749),这个线程就是我们想要的线程。
jstack命令
命令:pid为jvm进程号
作用:获取JVM线程堆栈快照
jstack <pid>
在线程堆栈中提供如下的几个信息:
1、jvm内部的线程ID(tid), 操作系统上对应的线程ID(nid)
2、线程锁的状态,以及线程栈的轨迹信息。
如上图,线程JStack-Test对应的操作系统上的线程ID为0x3749
nid=0x3749
拿到这个ID,是不是有点高兴?有没有发现这个ID就是上一步中用top命令得到的ID?
有了线程堆栈信息,就能够根据线程栈轨迹、线程的状态来判断是否有死锁,线程执行的代码是什么代码。从而在这些信息的基础上进一步帮助我们分析系统的瓶颈、线程死锁、CPU资源消耗等情况。
对于线程堆栈的分析,将另起一篇文章来讲解。
敬请期待!!!