【问题标题】:java.io.IOException: error=11java.io.IOException:错误=11
【发布时间】:2011-12-05 10:35:39
【问题描述】:

我在使用 Java ProcessBuilder 时遇到了一个奇怪的问题。代码如下所示(稍微简化)

public class Whatever implements Runnable
{

public void run(){
        //someIdentifier is a randomly generated string
        String in = someIdentifier + "input.txt";
        String out = someIdentifier + "output.txt";
        ProcessBuilder builder = new ProcessBuilder("./whateveer.sh", in, out);
        try {
            Process process = builder.start();
            process.waitFor();
        } catch (IOException e) {
            log.error("Could not launch process. Command: " + builder.command(), e);
        } catch (InterruptedException ex) {
            log.error(ex);
        }
}

}

无论.sh 读什么:

R --slave --args $1 $2 <whatever1.R >> r.log    

Whatever 的实例负载被提交到固定大小 (35) 的 ExecutorService。应用程序的其余部分等待它们全部完成——使用CountdownLatch 实现。在抛出以下异常之前,一切运行良好(Scientific Linux 5.0,java 版本“1.6.0_24”):

java.io.IOException: Cannot run program "./whatever.sh": java.io.IOException: error=11, Resource temporarily unavailable
    at java.lang.ProcessBuilder.start(Unknown Source)
... rest of stack trace omitted...

有人知道这意味着什么吗?根据java.io.IOException: error=11 的 google/bing 搜索结果,这不是最常见的异常,我完全感到困惑。

我的狂野和不那么有根据的猜测是,我有太多线程试图同时启动同一个文件。但是,重现该问题需要数小时的 CPU 时间,因此我没有尝试使用较小的数字。

非常感谢任何建议。

【问题讨论】:

  • 你用lsof检查过你的java进程的打开文件数吗?
  • 是 errno 11 还是 12 还是两者都有?

标签: java linux process processbuilder


【解决方案1】:

error=11 几乎可以肯定是EAGAIN 错误代码:

$ grep EAGAIN asm-generic/errno-base.h 
#define EAGAIN      11  /* Try again */

clone(2) 系统调用记录了EAGAIN 错误返回:

   EAGAIN Too many processes are already running.

fork(2)系统调用记录两个EAGAIN错误返回:

   EAGAIN fork() cannot allocate sufficient memory to copy the
          parent's page tables and allocate a task structure for
          the child.

   EAGAIN It was not possible to create a new process because
          the caller's RLIMIT_NPROC resource limit was
          encountered.  To exceed this limit, the process must
          have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE
          capability.

如果您的内存真的那么低,它几乎肯定会显示在系统日志中。检查dmesg(1) 输出或/var/log/syslog 以获取有关系统内存不足的任何潜在消息。 (其他东西会坏掉。这似乎不太合理。)

更有可能遇到每个用户的进程限制或系统范围的最大进程数。也许您的其中一个过程没有正确地重新捕获僵尸?这很容易通过检查ps(1) 的输出来发现:

while true ; do ps auxw >> ~/processes ; sleep 10 ; done

(可能每分钟或每十分钟检查一次,如果确实需要几个小时才能遇到麻烦。)

如果您没有收割僵尸,那么请阅读您必须对 ProcessBuilder 执行的任何操作,以使用 waitpid(2) 收割您死去的孩子。

如果您合法运行的进程数超出了 rlimit 允许的范围,则需要在 bash(1) 脚本中使用 ulimit(如果以 root 运行)或在 /etc/security/limits.conf 中为 @ 设置更高的限制987654339@财产。

如果您遇到系统范围的进程限制,您可能需要将更大的值写入/proc/sys/kernel/pid_max。有关一些(简短)详细信息,请参阅proc(5)

【讨论】:

  • 谢谢,这引导我朝着正确的方向前进。由于代码中的错误,在循环中创建了一个新线程,而不是重新使用现有线程,最终导致所描述的问题。
  • 所以不是builder.start() 调用特别是 有问题,而只是报告问题的那段代码?调试好。 :)
  • 嗯,确实是builder.start() 失败了,但它失败了,因为应用程序的另一部分已经耗尽了可用资源。正如您在帖子中提到的,分叉一个进程需要一定量的内存等。感谢您的帮助
【解决方案2】:

errno 11 表示“资源暂时不可用” 这通常是内存问题,可能会阻止创建线程或套接字。

errno 12 表示“无法分配内存”。这是获取内存失败是直接调用内存(而不是资源又需要内存)

我会尝试增加系统的交换空间,这应该可以避免这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多