记一次Java线上服务器CPU过载问题的排查过程

最近测试环境的订单模块经常性的挂掉,查看其CPU使用率达到177%。
CPU占用高一般是由以下情况导致的:

  1. 代码中存在死循环,导致应用一直占用着cpu。
  2. 某一张表数据量极大,查出来进行处理极其耗时,这时一般还伴随着内存溢出异常。
  3. 内存中存在虚拟机无法回收的对象,当内存不足的时候,gc一直在运行,导致CPU使用率飙升。

要确认是由于哪一种情况导致,一般可以按照以下步骤确定。
一. 使用TOP命令,查出是哪一个进程CPU占用率高,如下图所示,13339就是订单模块的进程ID,CPU占用率177.9%,
在这里插入图片描述二. 使用top -H -p13339(13339是Java进程的PID)命令找出了具体的线程资源占用情况(下面这张图是正常的,当时忘记截图保留了,知道此命令即可)在这里插入图片描述当时占用很高的线程ID是13341,13341,转成十六进制就是0x341d,0x341e

三. 执行jstack 13339 > jstack.txt,把队长信息导出来,用记事本打开,去匹配0x341d,0x341e
在这里插入图片描述可以发现是gc线程占用了CPU。

四. 定位到了四gc的问题,使用jstat -gcutil 10206 2000 50命令查看GC的回收情况
在这里插入图片描述E(Eden区)跟O(Old区)的内存已经被耗尽了,FGC(Full GC)的次数高达4447次,FGCT(Full GC Time)的时间高达3986秒,即平均每次FGC的时间为:3986/4447≈ 0.89秒。每隔一秒就进行一次GC操作,也就是说,Java进程都把时间花在GC上了,所以就没有时间来处理其他事情。

此时去查看订单模块的日志,发现内存溢出的情况:

20190827 17:31:41.473  [DiscoveryClient-HeartbeatExecutor-0] ERROR com.netflix.discovery.DiscoveryClient.renew():824 - DiscoveryClient-ORDER/order-200-186:order:8023 - was unable to send heartbeat!
java.lang.OutOfMemoryError: Java heap space

五.到这里,基本可以确定,是由于内存中存在虚拟机无法回收的对象,当内存不足的时候,gc一直在运行,导致CPU使用率飙升。但是是哪些对象不能回收呢,这就需要导出当时的内存快照dump文件,使用jmap -dump:file=du.dump 13339,把导出的du.dump用JProfiler打开(需要把dump后缀改成hprof才能用JProfiler打开),结果如下图:
在这里插入图片描述只从这张图仅仅可以看出前两个对象大小只占总大小的9%,其他什么也看不出来,所以需要有一份对比数据,这时我重启了订单模块,订单模块恢复正常,这时重新导出dump文件,这时的结果如下:
在这里插入图片描述通过对比发现,正常的dump文件前两个对象占用到了37%,异常的dump文件前两个对象只占用了9%,这说明异常的dump文件有其他大文件稀释了这个比例,通过仔细对比之后,发现异常的dump文件包含很多重复的对象
在这里插入图片描述查看这些相同对象里面的内容发现是存在ThreadLocal中的User对象,定位到具体代码,发现,在使用完成之后没有手动remove,导致对象越来越多,在某些情况下,ThreadLocal里面的对象,gc是没法回收的。至此就找到问题代码了。解决方案就是增加remove操作即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值