【问题标题】:Process Builder waitFor() issue and Open file limitationsProcess Builder waitFor() 问题和打开文件限制
【发布时间】:2023-08-25 12:17:01
【问题描述】:

我继承了一些代码:

Process p = new ProcessBuilder("/bin/chmod", "777", path).start();
p.waitFor();

基本上,出于某些古老且高度基于巫术的原因,将键/值对作为文件存储在磁盘上。我真的不想进入它。

但是,我留下了一堆 IO 异常:

Exception :Cannot run program "/bin/chmod": java.io.IOException: error=24, Too many open files
Message: Cannot run program "/bin/chmod": java.io.IOException: error=24, Too many open files

我的意思是在 10k - 数百万的范围内

我感觉 waitFor 调用是为了阻止这些发生,等待进程完成并退出,但是我认为 chmod 在文件实际关闭之前返回结果。有谁知道这是否会导致这些异常?

我的另一个倾向是在 java 端打开和关闭数千个文件的速度不够快,并且还有其他事情发生,也许是某种形式的文件缓冲区没有得到调用 fw.close() 时清除。

我对 java 还很陌生,这真是一个让我难过的怪异。 (很高兴该应用程序仍然以某种方式运行......在吐出一个非常大的日志文件之后)

任何人都可以想出一种方法来解决这个问题,清除缓冲区或将文件打开限制增加到 jvm 可以跟上自身的东西(假设是问题所在)

【问题讨论】:

标签: java java-io processbuilder


【解决方案1】:

我假设您正在循环运行这些 chmod 命令 - 否则我不明白为什么您会遇到这么多异常。您可能会遇到死锁,因为您没有读取衍生进程的输出。在ProcessBuilderRuntime.exec() 之前的日子里,这肯定会让我反感。

将您的代码 sn-p 更改为上述模式:

try {
    ProcessBuilder pb = new ProcessBuilder("/bin/chmod", "777", path);    
    pb.redirectErrorStream(true); // merge stdout, stderr of process

    Process p = pb.start();
    InputStreamReader isr = new  InputStreamReader(p.getInputStream());
    BufferedReader br = new BufferedReader(isr);

    String lineRead;
    while ((lineRead = br.readLine()) != null) {
        // swallow the line, or print it out - System.out.println(lineRead);
    }

    int rc = p.waitFor();
    // TODO error handling for non-zero rc
}
catch (IOException e) {
    e.printStackTrace(); // or log it, or otherwise handle it
}
catch (InterruptedException ie) {
    ie.printStackTrace(); // or log it, or otherwise handle it
} 

(信用:this site)看看这是否有帮助。

【讨论】:

  • 试过了,同样的异常发生
  • 我想我已经解决了,请在几分钟内检查我的答案 - 等待测试验证
  • 好的选择你的作为答案,因为它在解决方案中需要这个,检查我的帖子是否包含所需的额外行。
【解决方案2】:

感谢大家的帮助,这应该可以解决其他地方发生的大量怪事。

使用您的(Vinay)示例和流关闭:

try{ 
  fw.close();

  ProcessBuilder pb = new ProcessBuilder("/bin/chmod", "777", path);

  pb.redirectErrorStream(true); // merge stdout, stderr of process
  p = pb.start();

  InputStreamReader isr = new  InputStreamReader(p.getInputStream());
  BufferedReader br = new BufferedReader(isr);

  String lineRead;
  while ((lineRead = br.readLine()) != null) {
    // swallow the line, or print it out - System.out.println(lineRead);
  }

} catch (Exception ioe) {
  Logger.logException(Logger.WARN, ioe.getMessage(), ioe);
} finally {
  try {
    p.waitFor();//here as there is some snipped code that was causing a different
                // exception which stopped it from getting processed

    //missing these was causing the mass amounts of open 'files'
    p.getInputStream().close();
    p.getOutputStream().close();
    p.getErrorStream().close(); 

  } catch (Exception ioe) {
    Logger.logException(Logger.WARN, ioe.getMessage(), ioe);
  }
}

从 John B Mathews post 那里得到这个想法。

【讨论】:

  • 注意:为什么让 waitFor 和关闭输入流不能正常工作仍然没有意义,但我猜它是 java...
  • 很好,吉姆,但我仍然在您的finally 中看到了问题。我认为您需要将每个close 调用都放在自己的catch 中,否则如果在执行p.getInputStream.close() 时发生异常,您将无法关闭其他调用。该问题现在似乎已经消失,但以后可能会再次出现。
  • 即使输入和错误流与redirectErrorStream 合并,您是否真的需要关闭它们?即使您从未使用过输出流,您真的需要关闭它吗?
  • 您需要同时测试并找出答案。这篇文章真的很老了,我不认为代码已经存在了。
【解决方案3】:

如果不关闭文件,该过程似乎不太可能真正完成。这可能发生在非常大的线程中吗?或者也许其中一些实际上并没有完成(即,在某些情况下它挂在 waitFor 上)?

否则,我认为您将无法提高打开文件的限制。假设这是一个类 Unix 系统,“ulimit”命令可能就是你要找的。​​p>

【讨论】:

    【解决方案4】:

    如果您使用的是 JAVA 6,您还可以在 File 对象上尝试新的设置器(用于读取、写入、执行)。可能会慢一些,但应该可以。

    【讨论】: