9

我在使用 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被提交给一个ExecutorService固定大小的 (35)。应用程序的其余部分等待它们全部完成——使用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...

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

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

非常感谢任何建议。

4

2 回答 2

8

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)来收割你死去的孩子。

如果您合法运行的进程数超出了 rlimits 允许的范围,则需要ulimitbash(1)脚本中使用(如果运行为)或为属性root设置更高的限制。/etc/security/limits.confnproc

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

于 2011-12-05T10:54:15.707 回答
2

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

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

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

于 2011-12-05T10:46:01.990 回答