jar包运行一段时间后莫名其妙挂掉线上问题及处理方案
作者:心如活水
1、问题描述
springboot搭建的项目打包成jar包部署到Linux操作系统中,采用nohup java -jar 部署 jar 包后过一段时间(两三天)后莫名其妙挂掉(进程号PID被杀)。
2、问题定位
2.1 度娘一下
遇到这种问题,首先当然是去度娘找找看看有没有相似的人有这样的bug,看看别人的处理方法解决,结果当然是没找到合适的博客,所以就只能自己摸索摸索解决之道了。
2.2 基本操作
既然没有找到想要的,这种情况百分之九十九点九九九......的概率是内存泄露导致的。
那基本操作来一下
2.2.1 top、free -m 指令
先用top指令看下Linux系统中的进程号使用情况
从上图可看到,cpu的占用竟然干到了 100.3%以上,这么耗费cup资源,肯定就是程序有问题了。
接着用 free -m查看下内存使用情况
结果发现这个空闲内存越来越少了,还真的是内存有问题。
3、问题深入定位
上面只是初步知道程序有问题,但是还是不知道具体的问题再哪里?
就是这个问题在代码中哪里造成的还是不清楚
3.1 top -Hp PID 指令
输入PID指令将程序进程号的子线程使用系统资源的线程列举出来
从上图中可以看到733这个子线程占用了99.9%的cup使用率,这个线程肯定是有问题的,这个就要进入到JVM的栈中分析问题了,这里需要使用jstack工具进行分析问题。
3.2 jstack -l PID |grep -A 10 NID
因为在栈中的线程号是以16进制进行的,所以需要将上面733这个线程号转成16进制的数据,直接在Linux中转换: printf "%x\n" 733
然后采用jstack栈分析工具进行问题分析
jstack -l 655 |grep -A 10 0x2dd
这里的10是指打印10行的日志
找到这个子线程号,并且看到自己的报名和类,这个线程占用cpu 99.9%以上的资源就在类
ServerHandler的129行,赶紧去看看自己这个类的第129行到底写了什么东西。
这段代码直接导致了死循环,该段代码是希望读到输入流里面总的字节大小,但有时候因为网络原因无法一次读到结果,再加上while死循环,如果一直读不到,死循环就一直执行下去,故造成了死循环
4、解决
将上面导致死循环的代码注释掉改为缓存处理
5、后续
以上是一次线程问题的解决,其实一次线上问题解决没有那么快就排查出来的,如果涉及到堆问题,需要将堆问题、栈日志打印保存下来分析
堆文件生成:
jmap -dump:format=b,file=heap.hprof pid //保存了堆现场,b这里是字节的意思
(生成的堆文件采用mat分析软件定位问题)
- 栈日志生成:jstack pid > jstack.log //线程栈的现场
- gc执行情况:jstat -gcutil 6343 5000 //每隔5秒检查gc使用情况
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。