Java enables you to exectute a process on the host OS and to provide input (STDIN) to the process and read standard out (STDOUT) and standard error (STDERR). Each time that you execute a process via Runtime.exec() or ProcessBuilder.start() STDIN, STOUT, and STDERR are piped to the running JVM as an OutputStream or InputStream. For each stream there are two file descriptors and typically when the process terminates those streams are closed also closing the two file descriptors.
Even if you destroy the Process via Process.destroy() you may still be leaking file descriptors. The typical symptoms are as follows:
1. You see a growing number of named pipes in the output of lsof:
java 8654 rchapin 23w FIFO 0,6 0t0 26015 pipe
java 8654 rchapin 24r FIFO 0,6 0t0 26016 pipe
java 8654 rchapin 26r FIFO 0,6 0t0 26017 pipe
java 8654 rchapin 30w FIFO 0,6 0t0 26031 pipe
java 8654 rchapin 31r FIFO 0,6 0t0 26032 pipe
java 8654 rchapin 33r FIFO 0,6 0t0 26033 pipe
java 8678 rchapin 0r FIFO 0,6 0t0 26015 pipe
java 8678 rchapin 1w FIFO 0,6 0t0 26016 pipe
java 8678 rchapin 2w FIFO 0,6 0t0 26017 pipe
java 8680 rchapin 0r FIFO 0,6 0t0 26031 pipe
java 8680 rchapin 1w FIFO 0,6 0t0 26032 pipe
java 8680 rchapin 2w FIFO 0,6 0t0 26033 pipe
2. You start seeing the ‘Too many open files’ error in your log:
2012-07-06 02:39:27,260 (ERROR) (Thread-6) java.io.IOException: error=24, Too many open files
A good practice is to make sure to get a reference to each of the Streams and to explicitly close them, REGARDLESS of whether you actually utilize those streams.
Example:
Process process = Runtime.getRuntime.exec(“some command here”);
or
ProcessBuilder processBuilder = new ProcessBuilder(someCommandArray);
Process process = processBuilder.start();
// To close them
process.getInputStream().close();
process.getOutputStream().close();
process.getErrorStream().close();