我们使用JVM选项-verbose:gc
和-Xloggc:<path>
将垃圾收集事件记录到文件中。正如所料,Java进程保持对GC日志文件的锁定。
奇怪的是,当我们生成子进程时,子进程也保持对GC日志文件的锁定。这是一个问题,因为当我们的主Java进程退出时,我们无法删除GC日志文件,直到子进程也退出。
这是令人惊讶的,因为Java在打开文件时应该使用标志FD_CLOEXEC
以避免泄漏文件句柄到子进程。为什么GC日志文件不同?除禁用GC日志记录以外的任何解决方法吗?
下面的代码显示了一个简单的Java应用程序,它打开一个文件并启动一个在退出之前挂起3分钟的子进程。启用GC日志记录后,子进程会锁定GC日志文件(意外),但不会锁定常规文件my-file.log
(预期)。
// VM options:
// -verbose:gc -Xloggc:C:/test/log/gc.log
public static void main(String[] args) throws InterruptedException, IOException {
// Open a file for writing
new FileOutputStream("C:\\test\\log\\my-file.log");
// Start sub-process, but don't wait for it to exit
List<String> command = Arrays.asList("C:\\test\\log\\wait_test.bat", "180");
ProcessBuilder pb = new ProcessBuilder(command);
Process childProcess = pb.start();
// Wait 30 seconds
Thread.sleep(30 * 1000L);
// Exit without killing process or closing file
System.out.println("Exiting with process running: " + childProcess.isAlive());
}
wait_test.bat
的内容如下:
@echo off
REM %1 Time to wait in seconds
ping -n %1 localhost >nul
这是在Windows 7下使用Java版本1.8.0_101进行测试的。
更新:向JDK-8176717报告了Oracle的错误。