线上程序 cpu 占用过高、程序死锁,该如何定位问题?
假定你已经了解了运行时的数据区域和常用的垃圾回收算法,也了解了 Hotspot 支持的垃圾回收器
场景一:CPU 占用过高
cpu 占用过高要分情况讨论,是不是业务上在搞活动,突然有大批的流量进来,而且活动结束后 cpu 占用率就下降了,如果是这种情况其实可以不用太关心,因为请求越多,需要处理的线程数越多,这是正常的现象。话说回来,如果你的服务器配置本身就差,cpu 也只有一个核心,这种情况,稍微多一点流量就真的能够把你的 cpu 资源耗尽,这时应该考虑先把配置提升吧。
cpu 占用率长期过高,这种情况下可能是你的程序有那种循环次数超级多的代码,甚至是出现死循环了,或者死锁的情况。这个时候该怎么排查定位问题?
用 top 命令查看 cpu 占用情况
这样就可以定位出 cpu 过高的进程。在 linux 下,top 命令获得的进程号和 jps 工具获得的 vmid 是相同的。
用 top -Hp 命令查看线程的情况
可以看到是线程 id 为 23835 这个线程一直在占用 cpu
把线程号转换为 16 进制
记下这个 16 进制的数字,下面我们要用
用jstack工具查看线程栈情况 (过程省略)
我这里还是用前天的工具去查看检查下使用Arthas 的thread命令查看当前线程的堆栈情况
输出现在的线程栈,再通过 grep 命令结合上一步拿到的线程 16 进制的 id 定位到这个线程的运行情况,其中 jstack 后面的 23835 是第(1)步定位到的进程号,grep 后面的是(2)(3)步定位到的线程号。
从输出结果可以看到这个线程处于运行状态
案例代码
场景二:程序死锁
死锁并没有第一种场景那么明显,web 应用肯定是多线程的程序,它服务于多个请求,程序发生死锁后,死锁的线程处于等待状态(WAITING 或 TIMED_WAITING),等待状态的线程不占用 cpu,消耗的内存也很有限,而表现上可能是请求没法进行,最后超时了。在死锁情况不多的时候,这种情况不容易被发现。
开启 Arthas 查看线程
按照 CPU 使用率查看线程信息
显示指定线程的运行堆
发现了一个死锁,原因也一目了然
案例代码
总结
以上两种严格地说还算不上 jvm 的调优,只是用了 jvm 工具把代码中存在的问题找了出来。我们进行 jvm 的主要目的是尽量减少停顿时间,提高系统的吞吐量。但是如果我们没有对系统进行分析就盲目去设置其中的参数,可能会得到更坏的结果,jvm 发展到今天,各种默认的参数可能是实验室的人经过多次的测试来做平衡的,适用大多数的应用场景。如果你认为你的 jvm 确实有调优的必要,也务必要取样分析,最后还得慢慢多次调节,才有可能得到更优的效果。
评论