当为映射文件打开 FileOutputStream 时从 java.nio.MappedByteBuffer 读取会导致 "unsafe memory access" 错误
Reading from a java.nio.MappedByteBuffer when a FileOutputStream is open for the mapped file causes an "unsafe memory access" error
在调试工作中的问题时,我注意到在打开映射文件的 FileOutputStream 后尝试使用 MappedByteBuffer(通过调用 FileChannel.map() 从中创建 MappedByteBuffer 的文件)导致抛出以下异常:
"Exception in thread "main" java.lang.InternalError: 不安全内存访问操作出现故障"。
这是我拼凑的一个小代码示例,它始终触发异常:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class SomeClass {
// make sure the test file is at least this size, or you'll get a "cannot
// extend file to required size" exception when creating the buffer
private static int bufferSize = 10;
public static void main(String[] args) throws Exception {
File file = new File("/tmp/someFile");
FileInputStream fis = new FileInputStream(file);
ByteBuffer bb = getByteBuffer(fis);
// If you comment this out, the error goes away.
new FileOutputStream(file);
bb.get();
}
private static ByteBuffer getByteBuffer(FileInputStream fis) throws Exception {
return fis.getChannel().map(FileChannel.MapMode.READ_ONLY,
fis.getChannel().position(), bufferSize);
}
}
以上代码始终导致抛出上述异常。失败发生在 "bb.get()" 命令上,如果我注释掉打开 FileOutputStream 的代码则不会发生。
在我看来,错误的发生是因为我在其上调用 .get() 的 ByteBuffer 内存映射到我传递给 FileOutputStream 的同一个文件。我猜想有一些内部保护措施可以防止在打开文件时读取内存映射文件,但我无法弄清楚这是什么原因。
当文件上存在打开的 FileOutputStream 时,内存映射的 ByteBuffer 有什么特别之处可以防止读取操作被允许?我非常有兴趣了解此异常的内部结构。同样让我感到困惑的是,当为同一文件打开 FileOutputStream 时,打开 FileInputStream 并从中读取似乎没有类似的问题,即使这在功能上应该非常相似(从已经存在的文件中读取)为写作而打开)。
创建内存映射时,您是将文件的一个区域映射到内存中。
当您使用 FileOutputStream 时,您截断了文件并且您映射的内存区域不再存在。
如果您不截断该文件,它将具有您在执行映射时提供的大小。
在调试工作中的问题时,我注意到在打开映射文件的 FileOutputStream 后尝试使用 MappedByteBuffer(通过调用 FileChannel.map() 从中创建 MappedByteBuffer 的文件)导致抛出以下异常:
"Exception in thread "main" java.lang.InternalError: 不安全内存访问操作出现故障"。
这是我拼凑的一个小代码示例,它始终触发异常:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class SomeClass {
// make sure the test file is at least this size, or you'll get a "cannot
// extend file to required size" exception when creating the buffer
private static int bufferSize = 10;
public static void main(String[] args) throws Exception {
File file = new File("/tmp/someFile");
FileInputStream fis = new FileInputStream(file);
ByteBuffer bb = getByteBuffer(fis);
// If you comment this out, the error goes away.
new FileOutputStream(file);
bb.get();
}
private static ByteBuffer getByteBuffer(FileInputStream fis) throws Exception {
return fis.getChannel().map(FileChannel.MapMode.READ_ONLY,
fis.getChannel().position(), bufferSize);
}
}
以上代码始终导致抛出上述异常。失败发生在 "bb.get()" 命令上,如果我注释掉打开 FileOutputStream 的代码则不会发生。
在我看来,错误的发生是因为我在其上调用 .get() 的 ByteBuffer 内存映射到我传递给 FileOutputStream 的同一个文件。我猜想有一些内部保护措施可以防止在打开文件时读取内存映射文件,但我无法弄清楚这是什么原因。
当文件上存在打开的 FileOutputStream 时,内存映射的 ByteBuffer 有什么特别之处可以防止读取操作被允许?我非常有兴趣了解此异常的内部结构。同样让我感到困惑的是,当为同一文件打开 FileOutputStream 时,打开 FileInputStream 并从中读取似乎没有类似的问题,即使这在功能上应该非常相似(从已经存在的文件中读取)为写作而打开)。
创建内存映射时,您是将文件的一个区域映射到内存中。
当您使用 FileOutputStream 时,您截断了文件并且您映射的内存区域不再存在。
如果您不截断该文件,它将具有您在执行映射时提供的大小。