这月初,公司搜索服务发生了无响应事故,SSH登录到服务器上,cd、ll命令明显卡钝,top一下,负载90多了!服务器才16核啊!赶紧重启下resin服务,负载马上下来了。可是好景不长,服务器负载还是一点一点的涨上来,第二天就接近16了。
怎么回事?top看了下,占用CPU比较高的进程都是java进程。是代码问题吧?又找了下运维同事,查了下服务器性能监管日志,发现服务器CPU使用率大概每隔几小时涨一下,一涨就是100%,应该是有死循环了。好了,方向有了,找代码里的死循环。
好几千行代码查了一天,所有的循环代码都没问题啊!唉!急死了。眼看JVM又要开始吃CPU了,要是能直接查出JVM里的问题代码就好了!想到这灵光一现,top命令里有CPU占用时长数据啊,死循环线程会不断占用CPU时间,它的CPU时间应该是最长的那个。
top 查出进程号,再top -H -p 查出的进程号,显示出所有的线程!再按TIME+排序,呵呵,可找到你了,记下线程号。
再之后,就是从JVM里找出线程信息了。百度下,原来jvm提供了jstack命令。
jstack 线程号 > ~/jstack_out.txt
把jstack_out.txt下载到本地,用编辑器打开,我用了geany,window下推荐notepad++。现在线程号有了,JVM线程栈信息也有了,马上就可以找问题代码揪出来了!使用计算器或者在线工具,找线程号转换成十六进制,用转换的结果在线程栈信息里查找,找到nid=十六进制线程号的行,下面跟着的信息相信你会感到十分亲切了,嗯,和Java控制台输出的异常栈信息一样……
费了一番手脚之后,发现是HashMap内部死循环了。哦,原来HashMap用错了。这货是线程不安全的,每天嘴上说,结果多线程代码里还是手贱的写上了Map data = new HashMap()......果断加上一句data = Collections.synchronizedMap(data);打包部署上,服务器再了没压力了