System.gc() 调用时机与 MappedByteBuffer 文件锁定问题
System.gc() 用于请求垃圾收集器运行,尝试回收未使用的内存。但这里有个重要的前提:JVM 实现者有权决定是否真正执行。这就像现实生活中的'条件适用',一切都有免责声明。通常编写 Java 代码时,我们无需操心内存管理,交给 JVM 自动处理即可。但在某些特定场景下,比如性能基准测试(Benchmark),我们可能会在每次运行间隔手动调用它。
MappedByteBuffer 与文件删除
当我们需要最佳 IO 性能时,往往会用到 MappedByteBuffer。它直接将底层文件映射到内存。不过,Javadoc 里写得明明白白:
内存映射文件的许多细节固有地依赖于底层操作系统,因此是未指定的。当请求的区域未完全包含在该通道的文件中时,此方法的行为是未指定的。对该程序或另一个的底层文件的内容或大小进行的更改是否被传播到缓冲区是未指定的。没有指定将缓冲区的更改传播到文件的速率。
简单来说,大部分行为都交给了操作系统。这就引出了一个常见坑:
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class MappedFileGc {
public static void main(String[] args) throws IOException {
File tempFile = File.createTempFile("Temp", null);
tempFile.deleteOnExit();
RandomAccessFile raTempFile = new RandomAccessFile(tempFile, "rw");
FileChannel fChannel = raTempFile.getChannel();
MappedByteBuffer mappedBuffer = fChannel.map(FileChannel.MapMode.READ_WRITE, 0, 512);
fChannel.close();
raTempFile.close();
mappedBuffer = ;
(tempFile.delete()) {
System.out.println( + tempFile);
} {
System.out.println( + tempFile);
}
}
}

