总结:记一次内存溢出导致的tomcat频繁挂掉问题
一、问题背景
今天中午开始,几台线上服务器差不多在同个时间段相继挂掉,于是急忙排查故障原因。
二、原因分析
首先使用visualVM看资源使用情况,发现线程有2万多,甚至有的实例超过3万,于是通过jstack命令查看线程堆栈信息,看哪里代码生成太多的线程。
失望的是,只看到线程池名称,但是看不到具体是哪个代码类引起的问题。
于是另一种方式,换个角度,能否看到哪些对象占用空间大。使用jmap -dump命令,结果,生成的内存dump文件有20G,根本无法分析。
后来,同事提醒调小JVM最大使用内存(从30G调整到15G),观察了一段时间没有再出现问题(以为问题解决了,但是线程无限增大,理论上还是会内存溢出,后来发现确实不是这块的问题)。
第二天,又想了下这块原因,我们系统的线程池是公用的,理论上从代码层面产生的线程最多100个,不会更多,为什么会有超过3万?沿着这个思路想到,是否有人没有使用系统的线程池而是自己创建的线程池?
果然如此,经过搜索,发现有一个接口,调用一次就会创建一个最小线程数为10的线程池,搜了一个这个接口的调用情况,果然是在中午的时候开始高频率的调用,直至晚上8.30结束了调用,这也是调整JVM内存看似解决问题的原因。
三、结论
要慎用线程池,尽量使用公用线程池,这用线程比较可控。像我今天遇到的问题,3万个线程,每个线程配置了2M,就是60G,肯定会内存溢出的。
四、收获
这次排查问题,收获颇多,总结如下。
- 排查利器之日志:一定要知道tomcat有哪些日志,每种日志的作用。
1、比如bin目录下的hs_err_pid*.log,这个日志记录了致命错误,比如我这次遇到的内存溢出。
2、比如catalina.out,也会记录一些错误信息。
- 排查利器之virsualVM:至少从宏观上知道,是CPU标高,还是线程多,还是内存使用高。比如这次,从宏观上可以看到,是线程突增导致内存溢出。
- 排查利器之tomcat请求可视化:可以一目了然知道每个请求的时间周期内的调用次数。
以上是 总结:记一次内存溢出导致的tomcat频繁挂掉问题 的全部内容, 来源链接: utcz.com/z/512225.html