事发时间是上午十点,用户反馈访问不到系统了。由于正值使用高峰,运维人员马上重启了服务器,保证用户使用。服务器重启后,再次查看服务器参数,并无异常。查看服务器日志,有大量以下报错:
gc overhead limit exceeded
这个报错比较明显,就是堆内存溢出。这个系统已经稳定运行2年多了,没有出现过问题。用户是固定群体,不存在流量激增的情况。所以怀疑是自身代码的问题,找了相关同事,询问情况。确实,大概7天前更新过一版程序。
联系了运维人员,使用top命令查看cpu使用率,单个cpu保持在98%左右,说明cpu正在疯狂的处理任务,但是正值流量低峰,请求量不大,那cpu在忙什么呢???
使用命令jstat -gcutil pid 2000,监控堆内存的垃圾回收情况,发现老年代一直在暴涨
这个肯定就是有问题了,立刻获取了dump日志,获取命令:
jmap -dump:format=b,file=huoju_8-11.dump pid
然后使用MemoryAnalyzer工具对dump日志进行分析:
我们看一下到底是哪些对象占用空间比较多。
最靠前的几项,占用最多,可以看到,这是http的请求,应该是对外开放的rest接口之类。
可以看到一个ArrayList对象,这个对象占用了10.02%的空间,这个占用很大,继续看这个ArrayList持有了什么对象。
不看不知道,一看吓一跳。这个ArrayList里面竟然持有了380万个对象,而且通过inspector看到对象中的内容,380万个key,实际只有2个值,一直在不停的重复。现在基本可以得出一个结论,是因为堆内存中,突然多了380万个对象,影响了正常用户的使用。接下来,就是查一下代码,这380万个对象是如何产生的。最终,找到了相关代码,修复正常即可。