IOException:打开的文件过多

我试图在Linux上运行Jetty 7.0.1的Java webapp中debugging文件描述符泄漏。

由于打开的文件太多 ,请求开始失败,并且Jetty必须重新启动,该应用程序已经运行了一个月左右。

java.io.IOException: Cannot run program [external program]: java.io.IOException: error=24, Too many open files at java.lang.ProcessBuilder.start(ProcessBuilder.java:459) at java.lang.Runtime.exec(Runtime.java:593) at org.apache.commons.exec.launcher.Java13CommandLauncher.exec(Java13CommandLauncher.java:58) at org.apache.commons.exec.DefaultExecutor.launch(DefaultExecutor.java:246) 

起初我以为这个问题是用启动外部程序的代码,但是它使用的是commons-exec ,我看不出有什么问题:

 CommandLine command = new CommandLine("/path/to/command") .addArgument("..."); ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream(); Executor executor = new DefaultExecutor(); executor.setWatchdog(new ExecuteWatchdog(PROCESS_TIMEOUT)); executor.setStreamHandler(new PumpStreamHandler(null, errorBuffer)); try { executor.execute(command); } catch (ExecuteException executeException) { if (executeException.getExitValue() == EXIT_CODE_TIMEOUT) { throw new MyCommandException("timeout"); } else { throw new MyCommandException(errorBuffer.toString("UTF-8")); } } 

列出服务器上的打开文件我可以看到大量的FIFO:

 # lsof -u jetty ... java 524 jetty 218w FIFO 0,6 0t0 19404236 pipe java 524 jetty 219r FIFO 0,6 0t0 19404008 pipe java 524 jetty 220r FIFO 0,6 0t0 19404237 pipe java 524 jetty 222r FIFO 0,6 0t0 19404238 pipe 

当Jetty开始时,只有10个FIFO,几天之后就有数百个。

我知道在这个阶段有些模糊,但是你有什么build议去下一步看,或者如何得到关于这些文件描述符的更详细的信息?

您的外部程序行为不正确。 看看为什么它不这样做。

问题来自您的Java应用程序(或您正在使用的库)。

首先 ,你应该阅读整个输出(谷歌StreamGobbler),并pronto!

Javadoc说:

父进程使用这些流将输入提供给子进程并从子进程获取输出。 由于某些本地平台仅为标准输入和输出流提供有限的缓冲区大小,因此如果不及时写入输入流或读取子流程的输出流,可能会导致子进程阻塞甚至死锁。

其次waitFor()你的进程终止。 然后您应该关闭输入,输出和错误流。

最后 destroy()你的进程。

我的来源:

当你在Linux上运行时,我怀疑你的文件描述符已经用完了。 退房ulimit。 这里是描述这个问题的文章: http : //www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

不知道你的应用程序的性质,但我已经看到这个错误表现多次,因为连接池泄漏,所以这将是值得的检查。 在Linux上,套接字连接使用文件描述符以及文件系统文件。 只是一个想法。

除了查看根本原因问题,如文件泄漏等,以便合法增加“打开文件”的限制,并在重新启动后持续存在,请考虑编辑

 /etc/security/limits.conf 

通过添加这样的东西

 jetty soft nofile 2048 jetty hard nofile 4096 

在这里“jetty”是用户名。 有关limits.conf的更多详细信息,请参阅http://linux.die.net/man/5/limits.conf

注销然后再登录并运行

 ulimit -n 

验证已经发生了变化。 这个用户的新进程现在应该符合这个改变。 这个链接似乎描述了如何应用已经运行的进程的限制,但我还没有尝试过。

大型Java应用程序的默认限制1024可能太低。

你可以自己处理。 java中的exec返回一个Process对象。 间歇检查过程是否仍在运行。 一旦完成关闭进程STDERR,STDIN和STDOUT流(例如proc.getErrorStream.close())。 这将缓解泄漏。