我正在尝试在Linux上的Jetty 7.0.1中运行的Java webapp中调试文件描述符泄漏。
由于太多打开的文件而请求开始失败,应用程序已经开心运行了一个月左右,并且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,几天之后就有数百个。
我知道这个阶段有点模糊,但您对下一步的搜索方式有什么建议,或者如何获得有关这些文件描述符的更详细信息?
答案 0 :(得分:24)
问题来自您的Java应用程序(或您正在使用的库)。
首先,您应该阅读整个输出(Google for StreamGobbler)和pronto!
Javadoc说:
父进程使用这些流 提供输入和输出 子流程。因为有些原生 平台只提供有限的缓冲区 标准输入和输出的大小 溪流,未能及时写出来 输入流或读取输出流 子进程可能会导致 subprocess to block,甚至 死锁。
其次,waitFor()
您的流程终止。
然后,您应该关闭输入,输出和错误流。
最后 destroy()
您的流程。
我的消息来源:
答案 1 :(得分:8)
当你在Linux上运行时,我怀疑你的文件描述符已经用完了。查看ulimit。以下是一篇描述问题的文章:http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/
答案 2 :(得分:7)
您的外部程序行为不正常。看看它为什么不这样做。
答案 3 :(得分:5)
不知道你的应用程序的性质,但我已经看到这个错误多次出现,因为连接池泄漏,所以值得一试。在Linux上,套接字连接使用文件描述符和文件系统文件。只是一个想法。
答案 4 :(得分:5)
除了查看文件泄漏等根本原因问题,以便合法增加“打开文件”限制并在重新启动时保持这种限制,请考虑编辑
/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
验证更改是否已发生。此用户的新流程现在应该符合此更改。 This link似乎描述了如何对已经运行的进程应用限制,但我还没有尝试过。
对于大型Java应用程序,默认限制1024可能太低。
答案 5 :(得分:2)
你可以自己处理fds。 java中的exec返回一个Process对象。间歇性地检查进程是否仍在运行。一旦完成,关闭进程STDERR,STDIN和STDOUT流(例如proc.getErrorStream.close())。这将减轻泄漏。
答案 6 :(得分:0)
当您同时在多个文件中写入数据并且操作系统具有固定的Open文件限制时,会出现此问题。在Linux中,您可以增加打开文件的限制。
https://www.tecmint.com/increase-set-open-file-limits-in-linux/