2010-09-14 23 views
5

我有一些关于ProcessBuilder的问题。该程序基本上是一个调用命令行脚本的简单包装器。java: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类只是消耗标准输出/ stderr流并在控制台上显示它们的类。

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

问候,
阿尔诺

编辑:

  • 无论我使用的ProcessBuilder或 Runtime.getRuntime.exec(...),该 结果是一样的。
  • 爆发往往出现内存由 shell脚本调用UNIX '排序' 期间调用:

    好吧,这里:吉姆驻军的请求

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 
     } 
    } 
} 
+0

只是一个猜测:如果StreamConsumer实际上没有使用子进程的文本,那么文本可能会保存在一个不断增大的缓冲区中。 – 2010-09-14 12:01:43

+0

所有stdout&stderr已成功显示在控制台中 – dagnelies 2010-09-14 12:03:10

+2

如何测量内存消耗? _进程正在消耗内存...... JVM?贝壳?排序过程?在没有看到StreamConsumer的情况下,很难知道那里是否存在错误。你确定内存消耗对于进程是私有的还是仅仅是暂时的I/O缓冲区?你真的没有提供太多的东西继续下去。 – 2010-09-14 16:37:01

回答

2

如果你改变你的命令是这样的: sort -o big-text-file.sorted大文本文件

它总是一样吗?

+0

好点 - 也许是重定向错误。对此有何反应? – 2011-10-15 17:31:35

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(); 
//... 

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