作者:airchampion | 来源:互联网 | 2024-11-01 13:15
篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java服务问题快速排查指南相关的知识,希望对你有一定的参考价值。 问题 收到服务内存占用过大告警,登录虚拟机使用top发现每隔几秒ja
篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java服务问题快速排查指南相关的知识,希望对你有一定的参考价值。
问题
收到服务内存占用过大告警,登录虚拟机使用top
发现每隔几秒java进程占用的CPU就会暴增一次。
排查方向一:服务日志
- 使用
tail -fn 100 xxx.log
查看服务日志,发现频繁打印连接mail服务器失败错误,根据错误堆栈信息定位到业务代码位置 - 定位业务代码中的错误
排查方向二:JVM工具
若代码中未打印出错信息,可以考虑从jvm线程上入手。
- 使用
jps -mlv
获取java服务pid - 使用
top -H -p pid
查看高占用线程(此时pid为tid),CPU打满时有10多个线程都占10%左右 - 使用
jstat -gc pid 1000
及jstat -gcutil pid 1000
查看gc情况,发现大约每隔1到2秒jvm进行一次minor gc,老年代空间几乎不变,怀疑业务逻辑导致不断创建、释放新对象 - 记录步骤2中高占用率的几个线程tid,使用
printf "%x\\n" tid
将tid转为16进制 - 使用
jstack pid
打印线程状态,观察未出现死锁,搜索上一步的16进制数对应的线程,发现繁忙线程果真大都是gc线程,同时参杂着自定义线程池的线程,找到running状态的线程,根据线程调用栈定位到代码中执行的位置 - 业务代码中线程正在执行的是邮件发送操作,与方向一种错误位置吻合
- 定位到错误根源:该机器未开启外网访问权限,而代码业务逻辑中检测邮件发送连接失败则直接扔回队列中重试,因为没有设定最大重试次数导致频繁创建邮件消息体,耗尽堆空间,打开外网后问题解决
辅助分析
使用jmap -dump:format=b,file=dump.bin pid
生成堆转储文件,使用jhat dump.bin
或复制到有VisualVM等分析工具的机器上进行分析,可以发现占用堆空间最大的是char[]数组,打开其中几个发现内容都是一致的,都是邮件发送的消息体。
扩展
- 可以结合
free
、vmstat
、iostat
、netstat
等系统命令进行分析排查 - 将上述步骤写成脚本方便快速定位问题,网上已有不少例子,如 https://github.com/oldratlee/useful-scripts