5

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 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
        }
    }
}
4

2 に答える 2

2

コマンドを次のように変更した場合: sort -o big-text-file.sorted big-text-file

それはいつも同じですか?

于 2011-06-23T13:54:34.000 に答える
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();
//...

この動作は 1 回の呼び出しで発生していますか、それとも何度も実行した後に発生していますか?

于 2011-10-15T16:39:11.747 に答える