linux top过高问题拍查

1 篇文章 0 订阅

最近测试环境的订单模块经常性的挂掉,查看其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。
在这里插入图片描述

可以发现是gc线程占用几乎所有的CPU。
三. 执行jstack 13339 > jstack.txt,把堆栈信息导出来,用记事本打开,去匹配0x341d,0x341e

四. 定位到了是gc线程的问题,使用jstat -gcutil 13339 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对象

在这里插入图片描述

定位到具体代码,发现每次请求controller的时候都会把OnlineUser,放入到ThreadLocal里面,由于线程池的存在,导致线程一直复用,ThreadLocalMap里面的对象一直无法回收,持续增长,最终导致内存泄露。
在这里插入图片描述
至此就找到问题代码了。解决方案就是增加remove操作即可,如下图所示:

在这里插入图片描述
修改完成之后的内存快照如下,已经看不到线程对象,说明修改生效了。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值