java:ProcessBuilder使内存耗尽

时间:2010-09-14 11:55:22

标签: java processbuilder

我有一些关于ProcessBuilder的问题。 该程序基本上是一个调用命令行脚本的简单包装器。

当通过终端自行运行脚本时,内存消耗保持在2G以下。 通过java包装器运行脚本时,内存消耗会爆炸,甚至8G也会快速填满,从而导致内存不足错误。

启动流程的代码很简单:

public static int execute(String command) throws IOException
 {
  System.out.println("Executing: " + command);

  ProcessBuilder pb = new ProcessBuilder(command.split(" +"));
  Process p = pb.start();

  // display any output in stderr or stdout  
  StreamConsumer stderr = new StreamConsumer(p.getErrorStream(), "stderr");
  StreamConsumer stdout = new StreamConsumer(p.getInputStream(), "stdout");
  new Thread(stderr).start();
  new Thread(stdout).start();

  try {
   return p.waitFor();
  } catch (InterruptedException e) {
   throw new RuntimeException(e); 
  }
 }

StreamConsumer类只是一个消耗stdout / stderr流并在控制台上显示它们的类。

......问题是:为什么地球消耗会爆炸?

的问候,
阿诺

编辑:

  • 我是否使用ProcessBuilder或 Runtime.getRuntime.exec(...),. 结果是一样的。
  • 内存突发倾向于在由unix'sort'调用时出现 shell脚本调用:
sort big-text-file > big-text-file.sorted

根据Jim Garrison的要求编辑2:

好的,这是我省略的StreamConsumer类,因为它很简单:

class StreamConsumer implements Runnable
{
    InputStream stream;
    String descr;

    StreamConsumer(InputStream stream, String descr) {
        this.stream = stream;
        this.descr = descr;
    }

    @Override
    public void run()
    {
        String line;

        BufferedReader  brCleanUp = 
            new BufferedReader (new InputStreamReader (stream));

        try {
            while ((line = brCleanUp.readLine ()) != null)
                System.out.println ("[" + descr + "] " + line);
             brCleanUp.close();
        } catch (IOException e) {
            // TODO: handle exception
        }
    }
}

2 个答案:

答案 0 :(得分:2)

如果你改变这样的命令: sort -o big-text-file.sorted big-text-file

总是一样吗?

答案 1 :(得分:0)

也许是因为那些StreamConsumer线程不是守护进程,所以当你的进程返回时它们不会死并且会收集垃圾?你可以尝试:

//...  
final StreamConsumer stderr = new StreamConsumer(p.getErrorStream(), "stderr");
final StreamConsumer stdout = new StreamConsumer(p.getInputStream(), "stdout");
final Thread stderrThread = new Thread(stderr);
final Thread stdoutThread = new Thread(stdout);
stderrThread.setDaemon(true);
stdoutThread.setDaemon(true);
stderrThread.start();
stdoutThread.start();
//...

这种行为是针对单次调用还是多次执行后发生的?