背景
在一次上班时,用户反馈系统卡了,后台监控发现内存溢出了,频繁地触发了FullGC,但是内存却一直没有降下来。
而由于每次遇上这种问题时都是急急忙忙,需要尽快恢复服务供用户使用,所以排查的机会也不多,这次记录下之前收藏的排查方法,便于后续使用。
操作步骤
概览(只是忘记步骤看此处即可)
- 执行
jps
或ps
命令 查看当前服务器中运行的java应用进程号 jstack 进程号 > 指定文件名
生成线程快照(相比于jmap
对系统性能影响较小)top -Hp 进程号
查看进程中的线程状态,记录/截图该进程中占用资源最多的前几个线程号printf "%x\n" 线程号
命令将上一步获取到的线程号转为十六进制
- 在快照文件中根据
十六进制线程号
查找堆栈快照信息
详细步骤演示及说明
一、找到执行的java应用
- 执行
jps
或者ps
命令,查看当前服务器中运行的java应用进程号
jps
属于jdk的命令,简短地展示正在运行的java应用
ps
属于Linux的命令,会展示详细的vm参数信息(如有多个java应用可根据应用路径找到自己的服务)
二、生成线程堆栈快照
jstack 进程号 > 指定文件名
该命令对系统性能影响较小,不会像jmap
造成系统STW
(Stop The World)而无法运行,可以隔几秒或1分钟生成多几份
./jstack 6166 > /data/appsvr/rookie/stack1.out
三、查看进程中的线程状态,找到嫌疑线程
执行top -Hp 进程号
查看进程中的线程状态,记录占用资源最多的前几个线程号,因为数据会动态变化,建议截几张图保存,用于后面转换十六进制在快照文件中查询
四、转换嫌疑线程为十六进制
printf "%x\n" 线程号
命令将上一步获取到的线程号转为十六进制,用于在快照信息中进行查找,因为快照信息中记录的线程ID为十六进制
五、在快照文件中查找调用栈信息
- 在
Linux
中使用less
命令或者将文件拉下来根据转换的十六进制线程号查找栈信息 - 有时候占用CPU资源最多的线程号不一定是有用的信息,像我使用
1820
查找的内容就没有多少有效信息,反而使用19b7
找到了执行的java代码
反思
- 当时出现问题时定位到了是数据导出的问题影响的,而对于文件导出逻辑,系统应该有导出日志供运维查看,而不必从后台查找,例如导出参数,报表名称,数据量,操作用户,开始时间等等
- 还有一个目前未明白的是top命令监控的线程号和快照中实际运行的对应不上,看了程序没有启用多线程去处理导出,除了是生成快照时的处理线程跟监控时间差的问题外,还有其他原因导致吗?有大佬了解的话可以留下评论帮忙解答下