【问题标题】:IOException: Too many open filesIOException:打开的文件太多
【发布时间】:2011-01-03 22:03:55
【问题描述】:

我正在尝试调试在 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,几天后就有数百个。

我知道现阶段有点含糊,但您对下一步该往哪里看,或者如何获取有关这些文件描述符的更详细信息有什么建议吗?

【问题讨论】:

  • 添加了启动外部程序的代码。
  • 作为附加信息来源 netstat -anp --tcp|grep --color 可以是
  • 在 try-catch 之后添加 finally 块并关闭所有流。流可能没有正确关闭,因此您收到此错误。另请注意,linux 会处理打开文件中的打开连接数,因此请检查您的代码是否打开连接。

标签: java linux jetty ioexception file-descriptor


【解决方案1】:

当您同时在多个文件中写入数据并且您的操作系统对打开文件有固定限制时,就会出现此问题。在 Linux 中,您可以增加打开文件的限制。

https://www.tecmint.com/increase-set-open-file-limits-in-linux/

How do I change the number of open files limit in Linux?

【讨论】:

    【解决方案2】:

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

    /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 可能太低。

    【讨论】:

      【解决方案3】:

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

      首先,您应该阅读整个输出(Google for StreamGobbler),然后马上!

      Javadoc 说:

      父进程使用这些流 提供输入并从中获取输出 子进程。因为一些土生土长的 平台只提供有限的缓冲区 标准输入和输出的大小 流,未能及时写入 输入流或读取输出流 的子进程可能会导致 子进程阻塞,甚至 死锁。

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

      最后destroy()你的进程。

      我的消息来源:

      【讨论】:

      • 这是真正包含有用信息的正确答案。
      • 如果waitFor()成功了就不需要销毁进程了。该进程已经退出。
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        不知道您的应用程序的性质,但由于连接池泄漏,我已经多次看到此错误,因此值得一试。在 Linux 上,套接字连接使用文件描述符以及文件系统文件。只是一个想法。

        【讨论】:

          【解决方案6】:

          当您在 Linux 上运行时,我怀疑您的文件描述符已用完。查看 ulimit。这是一篇描述该问题的文章:http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

          【讨论】:

          • 这可能会让您获得长达 2 个月的运行时间! (这充其量只是一个创可贴。)
          • 您重复了症状,但不是真正的治愈方法。
          • 事实上,我确实出于其他原因提高了/etc/security/limits.conf 的限制。
          • 这至少可以解决我们的问题。应用程序(第 3 方)打开的次数超过 1024。没有泄漏,但只是限制太低。按照article 中的建议将限制设置为 65535。看起来问题已经解决了。
          猜你喜欢
          • 2011-05-16
          • 1970-01-01
          • 2016-07-18
          • 2012-07-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多