我们在 2015 年左右遇到了类似的问题,因为 Win7/x64 上的用户经常发现程序终止后未删除的剩余文件。经过一些研究和反复试验,我们发现它只发生在最近进行内存映射的文件中,并通过避免对我们想要很快/稍后删除的文件进行内存映射来修复它。
FileChannelImpl.transferFromFileChannel
内存映射传输源。(取决于您的 JVM — 我基于 OpenJDK。)虽然 JVM 通过取消映射在复制后进行清理,从而使创建的视图无效,但操作系统可能会将实际清理延迟到另一个时间点。在此之前,该文件有一个活动的(但不可访问的)内存映射,可能会阻止取消链接。
这个问题似乎相关:如何正确关闭 MappedByteBuffer?
供参考:jdk11/sun.nio.ch.FileChannelImpl#transferFromFileChannel
private long transferFromFileChannel(FileChannelImpl src,
long position, long count)
throws IOException
{
if (!src.readable)
throw new NonReadableChannelException();
synchronized (src.positionLock) {
long pos = src.position();
long max = Math.min(count, src.size() - pos);
long remaining = max;
long p = pos;
while (remaining > 0L) {
long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
// ## Bug: Closing this channel will not terminate the write
MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);
try {
long n = write(bb, position);
assert n > 0;
p += n;
position += n;
remaining -= n;
} catch (IOException ioe) {
// Only throw exception if no bytes have been written
if (remaining == max)
throw ioe;
break;
} finally {
unmap(bb);
}
}
long nwritten = max - remaining;
src.position(pos + nwritten);
return nwritten;
}
}