开发案例——文件句柄数过多

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/abcyyjjkk/article/details/82181977

问题描述:使用 lsof 查看 java 进程(tomcat)的文件句柄数过多,并且持续增加而未见减少。

定位方法:1.使用 lsof 查看详细的句柄信息,发现存在大量的“pipe”和“eventpoll”(占总句柄数的80%以上),如图:

     2.基本可以确定是由于代码中存在打开文件/创建连接后未进行释放/销毁导致;但由于tomcat中部署模块较多代码量巨大,日志文件内容也很多很难从中找出有意义的信息(文件句柄数超出系统限制后,会刷出很多连接异常、文件无法访问异常,这些信息会掩盖掉真正出问题的地方),需要先定位到具体模块才好进行进一步的代码审查(否则代码审查的工作耗时太长)。

3.将各模块分开部署到不同的机器,并确保复现条件(确保正常操作,以及人为制造后期断线等异常情况),逐步缩小范围。
比如:共A,B,C,D,E,F,G,H八个模块
① 首先将A,B,C,D部署于1号机器、E,F,G,H部署于2号机器;若1号没问题,2号出问题,则可确定出问题的模块是在E,F,G,H中;
② 然后将A,B,C,D,E,F部署于1号机器、G,H部署于2号机器;若1号出问题了,2号没问题,则可确定出问题的模块是在E,F两个模块中;
③ 将 A,B,C,D,E,G,H 部署于1号机器、F部署于2号机器;若1号没问题,2号出问题了,则最终可确定出问题的模块是F模块。

(注意:这里如果两台机器都同时发现问题,则说明多个模块都存在问题,应当打乱顺序重新测试,应当找出是具体是哪些模块存在问题(或者说找出无问题的模块);多个模块均存在问题时,应当考虑是否这些模块中引入的基础库中存在问题,或者找出其它共性。)

针对F模块进行代码审查,发现该模块中存在一个重连任务,在 startup() 出现异常时,会导致 shutdown() 未执行;并且重连之前的连接也未进行释放(关闭操作)。

 继续查看 startup(), shutdown() 的代码,发现在 startup() 中不存在异常处理的代码,也就是说,如果 connector.connect(...), connFuture.getSession() 出现异常,会导致 connector, connFuture 未释放。

 

问题解决:

本案例修改建议:

  1. 在 startup() 内创建连接对象前判断是否已存在连接并判断是否连接正常;若正常则直接返回,若不正常则应当释放之前的连接;
  2. 在 startup() 内需添加异常处理,若connect(), getSession() 出现异常,则应当释放之前的连接;

 

注意,文件句柄过多的问题并不仅限于NIO网络连接,有可能出现问题的有:

  1. 打开文件未释放
  2. 打开管道未释放
  3. 建立网络连接未释放(pipe,eventpoll多出现在 NIO 网络编程未释放资源 —— selector.close())
  4. 创建进程调用命令未释放(Runtime.exe(...) 得到的 Process, InputStream, OutputStream 未关闭,这也会导致 pipe,eventpoll 未释放)
  5. mina库使用NIO时未使用connector.dispose();
  6. netty3库使用NIO时未使用bootstrap.shutdown() 或bootstrap.releaseExternalResources();

netty4使用NIO时未使用 eventLoopGroup.shutdownGracefully();

 

猜你喜欢

转载自blog.csdn.net/abcyyjjkk/article/details/82181977