最近新版本发布后,在运行一段时间后程序突然无响应了,观察监控,发现JVM堆内存占用在某个时间点突然飙升,最终导致应用无响应:
重启Tomcat后,应用恢复正常,并且后续时间没有发生内存上涨问题。
分析这个JVM内存曲线,他是直线上升的,以前遇到过类似的场景,会导致这种直线(匀速)上升的,一般是一个死循环导致的,如果是普通请求资源泄露的话,上升曲线不会这么平稳,会和请求量有一定的关系。
死循环导致这个线程的资源无法释放,随着循环次数的增多,累积的对象越来越多,最终导致堆内存耗尽。
那要如何定位到具体的死循环位置呢?这个是个难题。之前遇到类似的问题是通过dump生产环境的JVM内存来分析,耗时耗力。结合之前的经验,这次我直接去nginx日志搜索响应码为504的请求,果不其然,在内存飙升时间点附近,有一个被响应504的请求。
504是什么响应码呢?这个响应码比较少遇到,指的是网关超时 (Gateway timeout)。当一个请求到Tomcat后,Tomcat如果陷入死循环,那么这个请求自然无法得到响应,nginx等待响应超时,响应给用户504。
504响应时间点和内存飙升时间点对的上,那么大概率就是这个接口导致的,详细分析这个接口的代码,发现了在特殊参数的情况下,会进入死循环,修改后问题解决。
总结:
- 观察JVM内存曲线,是否是匀速上升
- 搜索Nginx响应码为504的日志,查看日志时间是否和内存上升时间点匹配
- 分析Nginx响应码为504的请求,确认是否存在死循环逻辑