代码之家  ›  专栏  ›  技术社区  ›  Mirko N.

IOException:打开的文件太多

  •  25
  • Mirko N.  · 技术社区  · 15 年前

    我试图调试一个JavaWebApp中的文件描述符漏洞,它在JETT7.7.1上运行。

    当请求因以下原因而开始失败时,应用程序已经愉快地运行了一个月左右 打开的文件太多 ,码头必须重新启动。

    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,几天后,就有数百个fifo。

    我知道在这个阶段有点模糊,但是你对下一步在哪里查找,或者如何获得关于这些文件描述符的更详细信息有什么建议吗?

    7 回复  |  直到 6 年前
        1
  •  7
  •   Thorbjørn Ravn Andersen    15 年前

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

        2
  •  24
  •   ofavre    13 年前

    问题来自你的Java应用程序(或者你正在使用的一个库)。

    弗斯特 ,您应该阅读整个输出(google for streamgobbler),并立即!

    Javadoc 说:

    父进程使用这些流 输入并从中获取输出 子流程。因为一些本地人 平台只提供有限的缓冲区 标准输入输出尺寸 流,未能及时写入 输入流或读取输出流 子进程的 要阻塞的子进程,甚至 僵局。

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

    最后 destroy() 你的过程。

    我的消息来源:

        3
  •  8
  •   Greg Smith    15 年前

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

        4
  •  5
  •   alasdairg    15 年前

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

        5
  •  5
  •   Community CDub    8 年前

    除了调查诸如文件泄漏等根本原因问题外,为了合法地增加“打开的文件”限制并在重新启动时保持这些限制,请考虑编辑

    /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 似乎描述了如何对已经运行的进程应用限制,但我没有尝试过。

    默认限制1024对于大型Java应用程序来说可能太低。

        6
  •  2
  •   allenjsomb    14 年前

    你可以自己处理FDS。Java中的Exchange返回进程对象。间歇性检查进程是否仍在运行。完成后,关闭进程stderr、stdin和stdout流(例如proc.geterrorstream.close())。这将减少泄漏。

        7
  •  0
  •   Vpn_talent    6 年前

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

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

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