環境
- Windows 7
- Java 8
- Spring Framework 5.0.2
事象
エラーログにて「ファイルを開きすぎです」というFileNotFoundExceptionが多数表示される。
Caused by: java.io.FileNotFoundException: /user/local/apache-tomcat-8/**/sample/WEB-INF/**/sample.jar (ファイルを開きすぎです)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:225)
at java.util.zip.ZipFile.<init>(ZipFile.java:155)
at java.util.jar.JarFile.<init>(JarFile.java:166)
at java.util.jar.JarFile.<init>(JarFile.java:103)
・
・
(省略)
・
・
Caused by: java.io.FileNotFoundException: /user/local/apache-tomcat-8/**/sample/WEB-INF/**/sample.jar (ファイルを開きすぎです)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:225)
at java.util.zip.ZipFile.<init>(ZipFile.java:155)
at java.util.jar.JarFile.<init>(JarFile.java:166)
at java.util.jar.JarFile.<init>(JarFile.java:103)
原因
- プロセスのクローズ漏れによるエラーが原因
ProcessBuilderを使用すると、バックグラウンドでInputStream・OutputStream・ErrorStreamが勝手にオープンされるため、全てのストリームをクローズしないとリソース不足に陥るかららしいです。
package sample;
import java.io.IOException;
public class ProcessExecutor {
public void execute(String... command) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
process.waitFor();
process.destroy();
}
}
対処方法
- Process.destroy()の前に必ずすべてのストリームをcloseする。
以下のように全てのストリームに対して、しっかりとクローズ処理を追加することでエラーが解消された。
package sample;
import java.io.IOException;
public class ProcessExecutor {
public void execute(String... command) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
process.waitFor();
// 以降追加
process.getInputStream().close();
process.getOutputStream().close();
process.getErrorStream().close();
process.destroy();
}
}