【问题标题】:java: ProcessBuilder makes a memory hogjava:ProcessBuilder 会占用内存
【发布时间】:2010-09-14 11:55:21
【问题描述】:

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

通过终端自行运行脚本时,内存消耗保持在 2G 以下。 通过java wrapper运行脚本时,内存消耗爆炸,甚至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(...), 结果是一样的。
  • 在由 调用的 shell 脚本:
sort big-text-file > big-text-file.sorted

应吉姆·加里森的要求编辑 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
        }
    }
}

【问题讨论】:

  • 只是猜测:如果 StreamConsumer 并没有真正消费子进程的文本,那么文本可能会保存在一个不断增加大小的缓冲区中。
  • 所有stdout & stderr都成功显示在控制台
  • 你是如何测量内存消耗的? 哪个进程正在消耗内存……JVM?贝壳?排序过程?没有看到 StreamConsumer 很难知道那里是否存在错误。您确定内存消耗是进程私有的还是只是临时 I/O 缓冲区?你真的没有提供太多的东西。
  • 我们使用排队系统(Sun 的网格引擎)来测量和限制作业的内存消耗。
  • 这似乎与此处讨论的问题相同:stackoverflow.com/questions/1124771/…

标签: java processbuilder


【解决方案1】:

如果您像这样更改命令: sort -o big-text-file.sorted 大文本文件

总是一样吗?

【讨论】:

  • 好点 - 可能是重定向错误。对此有何反应?
【解决方案2】:

也许是因为那些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();
//...

这种行为是单次调用还是多次调用后发生?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多