资源泄漏导致程序无法响应

※ 问题

程序提交测试后,发现了一个问题,某些情况下,在运行了几十个小时、甚至更长时间之后,服务端会失去响应,从而导致客户端无法连接上来。这个问题不容易重现,同时重新运行服务端后即可恢复正常。

※ 调试

这个问题出现过数次,但一直没有总结出固定重现的方法,且每次出现也都是长时间的运行之后,因此没有明确的解决思路。

由于没有固定重现方法,所以只能等待。在这期间,仔细分析了客户端与服务端之间连接和通信的实现代码,并无可疑之处,而且这段代码很长时间里没有修改过,所以粗略感觉下来问题不在这里。

终于等到了问题的重现!

经过仔细观察,问题出现后的现象是这样的:客户端去连接服务端,会提示连接失败;观察服务端,系统日志里出现了很多打印,其中比较值得关注的是 socket 监听失败。

服务端在开发过程中实现了日志的功能,这对问题的分析起了很大的帮助。分析日志,发现里面有很多的打开文件的错误记录,分析下来那就是打开了很多文件,以至于无法打开更多的文件,从而导致 socket 监听失败,引起客户端无法连接上来。

进入了 /proc/<server pid>/fd/ 这个目录,ls 了一下,结果有大量的输出,其中几乎所有的文件已经删除,但有好多文件句柄没有释放。使用 ls -1 | wc -l 统计了一下,目前已经打开了 1024 个文件,这已经是每个进程打开文件的默认上限了(这可以从 ulimit -a 看出来)。虽然几乎所有的文件已经删除,但从未释放的文件句柄,还可以看出这些文件的所在路径。

结合业务程序的实现代码分析,原因就清楚了,有一个模块的实现里会经常性地产生临时文件,操作完成后会删除这个临时文件,但问题是没有关闭文件句柄。在该模块运行一定次数后,未释放的文件句柄越来越多,直到达到默认的上限,从而导致了这个问题。

※ 解决

补上关闭文件句柄的操作即可。

Read More: