Process.destroy()の前に必ずすべてのストリームをcloseすること
次のような間違いを含んだコードがあります。
// 同じようなことがRuntime.exec(...)でも起こる
ProcessBuilder pb = new ProcessBuilder(args);
Process proc = pb.start();
InputStream in = proc.getInputStream();
// ・・・ここでスレッドのストリームから読んで処理をする
proc.waitFor();// ・・・最後に、finallyブロックで「InputStreamを」クローズして、プロセスを終了する(不十分)
in.close();
proc.destroy();
プロセスを作成して、ストリームをキャプチャして、最後にそのストリームをクローズしています。ごく一般的な考え方によるコードだと思います。
しかし、これは間違いです。上記コードをループで繰り返すと、IOException がスローされ、'Too many open files'だと言われます。
これは、ProcessBuilderを使用するとバックグラウンドでInputStream, OutputStream, ErrorStreamが勝手にオープンされるため、全てのストリームをクローズしないとリソース不足に陥るからでした。
この問題を解決するには、次のように全てのストリームをちゃんとクローズしなくてはなりません。下のほうの2行が追加部分です。
ProcessBuilder pb = new ProcessBuilder(args);
Process proc = pb.start();
InputStream in = proc.getInputStream();
// ・・・ここでスレッドのストリームから読んで処理をする
proc.waitFor();// ・・・最後に、finallyブロックで「全ての」ストリームをクローズする
in.close();
proc.getOutputStream().close(); (←追加)
proc.getErrorStream().close(); (←追加)
proc.destroy();
ちなみにProcess.destroy()のjavadocには次のような説明しかありません。これでは同じような過ちをする人があとを絶たないでしょう・・・。
サブプロセスを終了します。この Process オブジェクトが表すサブプロセスは強制終了されます。
javadocを修正するようにいくつかのバグレポートで言及されています。早く反映されると良いのですが・・・。