Runtime.exec()でToo many open Files

あるシステム(JRE1.4.2_05 on Soralis8)を運用している中で、Too many open FilesのIOExceptionが発生することがありました。
pfilesコマンドでプロセスが掴んでいるファイルディスクリプタを覗いてみると、

S_IFIFO mode:0000

という、FIFOがたくさんできちゃって残りっぱなしになっています。
trussでシステムコールを監視してみると、

pipe()                                          = 7 [8]
pipe()                                          = 10 [12]
pipe()                                          = 13 [14]
fork1()                                         = 29021

とforkした後に、closeが

close(7)                                        = 0
close(12)                                       = 0
close(14)                                       = 0
close(8)                                        = 0

と4回しか呼ばれてないことが分かりました。実際にRuntime.exec()を実行しているのは、ミドルウェアの部分なので、ソースを見ることはできないのですが、おそらくProcessオブジェクトの標準入力および標準エラーをクローズしていないと推測されます。

簡単なプログラムを作り実行してみると確かに3本のストリーム全てをクローズするとFIFOが残りっぱなしになるなんてことはありません。逆に標準出力だけクローズすると同現象が起こります。

import java.io.*;

class TooManyFilesTest{
        public static void main(String[] args) throws Exception {
                for(int i=0; i<= 300; i++) {
                        Process p = Runtime.getRuntime().exec("cat");
                        InputStream in = p.getInputStream();
                        PrintStream out = new PrintStream(p.getOutputStream());
                        out.println("ABC"+ i);
                        out.close();
                }
                Thread.sleep(60000); //この隙にpfiles
        }
}


ということで教訓

Runtime.execするときは、Processオブジェクトの3つのストリーム(stdout, stdin, stderr)の全てをクローズせよ。