提问者:小点点

当为映射文件打开 FileOutputStream 时,从 java.nio.MappedByteBuffer 读取会导致“不安全的内存访问”错误


在调试工作中的问题时,我注意到在打开 FileOutputStream 到映射文件(通过调用 FileChannel.map() 从中创建 MappedByteBuffer 的文件)后尝试使用 MappedByteBuffer,始终会导致引发以下异常:

“线程“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()”命令上,如果我注释掉打开FileOutpuStream的代码,则不会发生失败。

在我看来,发生错误是因为我调用.get()的ByteBuffer内存映射到了我传递给FileOutputStream的同一文件。我猜测,如果文件被打开,有一些内部保护措施可以防止内存映射文件被读取,但我无法弄清楚这是什么原因。

当文件上存在打开的FileOutputStream时,内存映射的ByteBuffers有什么特殊之处?我很想了解这个异常的内部。同样令我困惑的是,当FileOutputStream为同一文件打开时,打开FileInputStream并从中读取似乎没有类似的问题,尽管这在功能上应该非常相似(从已经打开用于写入的文件中读取)。


共1个答案

匿名用户

创建内存映射时,将文件的一个区域映射到内存中。

使用 FileOutputStream 时,会截断该文件,并且映射的内存区域不再存在。

如果不截断文件,它将具有执行映射时给定的大小。