暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Linux系统Java进程CPU高消耗问题分析

IT那活儿 2020-08-15
3281
[
概     述
]

当应用系统出现卡顿或者应用程序响应速度非常慢的时候,我们需要登录到应用所在主机进行查看、分析问题原因。

常用来排查Java进程问题命令:

  • 使用top命令查看主机资源总体使用情况,及相关Java进程占用主机资源情况;

  • 使用vmstat 2 5命令查看主机CPU、内存使用率;

  • 使用df -h命令查看主机文件系统使用率;

  • 使用netstat -na命令收集主机网络连接情况;

  • 使用pstree -p PID | wc -l查看占用CPU资源较高的进程内的线程数;

  • 使用${JAVA_HOME}/bin/jstat -gcutil PID 1000 10查看占用CPU资源较高的进程GC情况;

  • 使用${JAVA_HOME}/bin/jmap -dump:live,format=b,file=PID.hprof PID导出占用CPU资源较高的进程堆快照信息,用来统计当前JVM堆中存放了哪些对象信息;

  • 使用${JAVA_HOME}/bin/jstack PID > stack_PID.log导出占用CPU资源较高的线程栈快照信息,来最终定位占用CPU过高的代码模块。

[
常见CPU高消耗原因
]

1、大量高并发密集型计算

2、高并发的I/O读写

3、堆内存无法有效回收,FULLGC频繁

4、程序死循环

5、程序逻辑请求堵塞

[
分   析   方   法
]

案例1:Java进程耗用CPU高,但未触发FULLGC的情况

1、查看进程使用CPU、MEM情况

使用命令:top

可以看到PID为4267,USER为dform的进程CPU使用率高达1464.2%(即消耗当前主机14.64个CPU),严重超高。使用命令cat/proc/cpuinfo | grep processor |wc –l 可查看当前主机逻辑CPU个数。

2、根据问题进程的PID查询该进程的线程使用CPU、MEM情况

使用命令:top-p 4267-H

红框标出的10几个线程耗用CPU都接近或者超过了100%(即该进程下有10几个线程耗用CPU都高达1个左右)。

3、导出问题进程的线程栈信息

使用命令:

连续导出多个线程栈(stack)快照文件,每次导出间隔5s-10s

${JAVA_HOME}/bin/jstack4267 > stack_4267_1.log

${JAVA_HOME}/bin/jstack4267 > stack_4267_2.log

${JAVA_HOME}/bin/jstack4267 > stack_4267_3.log

4、将问题线程的PID(十进制)转换成十六进制的nid

使用命令:我们选取如下两个线程为例

(1)线程PID4477,转换之后的十六进制nid为117d

printf "%x\n"4477

(2)线程PID4542,转换之后的十六进制nid为11be

5、根据nid在第3步中导出的线程栈(stack)快照文件中查找对应的线程

(1)根据nid=0x117d查找到正在运行的程序代码模块,红框标出是该线程最后正在做的事物(线程执行顺序要从下向上看),绿框标出是应用侧代码模块。

(2)同理,根据nid=0x11be查找到正在运行的程序代码模块

最后将上述分析结果和线程栈(stack)快照文件一并反馈给应用侧核查和处理。

案例2:Java进程耗用CPU高,而且频繁触发FULLGC的情况

导致Java进程频繁FULLGC的原因有:

(1)应用代码逻辑设计不合理,对象创建太多,而且对象使用完后未及时释放资源,或者已不再有用的对象相互之间存在引用,导致该对象无法进行回收;

(2)消费者消费速度慢(或停止消费),而生产者不断往队列中投递任务,导致队列中任务累积过多,任务对象占用堆内存太多而产生FULLGC;

(3)应用进程创建线程太多(每个线程需要分配线程栈内存),也可能导致内存溢出OOM,触发FULLGC;

注:分析FULLGC的问题,除了要分析案例1中的线程栈(stack)快照信息外,还要导出JVM堆(heap)进行分析。

1、使用命令:导出JVM堆(heap)快照信息

${JAVA_HOME}/bin/jmapdump:live,format=b,file=17074.hprof17074

注:堆(heap)快照文件一般都比较大,有几个G大小(基本和参数-Xmx设置大小一致)。

2、使用Java堆分析工具MAT(MemoryAnalyzer tool)分析堆内存中对象占用情况

通过对堆内存快照文件17074.hprof的分析,发现有以下一些对象占用内存较多:

结合日志信息分析,应用一次性经过代理节点从数据节点中获取大量数据到堆内存中,并同时几条请求同时进行,该代理节点出现JVM堆内数据占用较大导致内存溢出,FULLGC无法回收,此后一直频繁FullGC。另根据GC信息分析,大约7个小时就会有一次较多请求刷新导致内存占用过多的情况。

最后将分析结果反馈给应用侧核查和处理。

[
处理建议
]

1、结合中间件侧分析结果应用侧核查对应的代码模块中是否有多线程高并发或者涉及网络间IO等,导致线程CPU耗用高的代码,并优化;

2、结合中间件侧分析结果应用侧核查相应的代码模块所涉及的业务是否存在逻辑问题,并优化;

3、对于长时间处于CPU高消耗的进程,收集完top、线程栈(stack)快照、堆(heap)快照等信息之后,可找合适时间重启该进程。

文章转载自IT那活儿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论