Memory Mapped File
在java早期版本中,使用FileSystem传统的API来访问系统文件。这种场景下,JVM发起read()、write()系统调用从OS kernel到JVM传输数据。JVM使用它的内存空间加载、处理文件。如果文件比较大,处理起来比较慢。OS使用页的方式处理文件,而JVM使用字节流的方式,不能匹配文件页,因此需要从OS内核空间拷贝文件的内容到JVM空间。从jdk1.4开始,提供了MappedByteBuffer,用于帮助建立一个从JVM空间到OS文件系统页的映射的虚拟内存。这种方式避免了因为拷贝文件内容的带来的开销。OS使用虚拟内存在内核空间之外缓存文件,可以被非内核进行所共享。java直接映射文件页到MappedByteBuffer,然后处理文件,不需要将其加载到JVM里面。
MappedByteBuffer直接使用FileChannel的map方法,对虚拟内存的内容进行映射。MappedByteBuffer对象工作起来像buffer,但是它的数据存储在虚拟内存的文件里。get()方法可以从文件里获取数据。put()方法更新数据,对文件的其他读者修改可见。
这样做的好处,如下:
- JVM直接在虚拟内存上处理,不需要发起read()、write()系统调用。
- JVM不需要在它的内存空间中加载文件,处理大数据文件更有效率。
- OS基本上只需要关注虚拟内存的读写,不需要使用JVM。
- 提供文件的部分映射。
- 虚拟内存的文件数据不需要buffer进行传递。
如果增加了准备写入的文件大小,并且大于了文件本身的大小,导致MappedByteBuffer 在写模式中匹配的大小变得更大,但是在读模式中会抛出IOException。
提供了如下三种映射模式:
- READ_ONLY: Read only
- READ_WRITE: Read and update the file
- PRIVATE: Change in MappedByteBuffer will not reflect to File.
映射同一个文件的多个MappedByteBuffer之间不可见可以通过PRIVATE映射模式,创建私有的副本。
如果在READ_ONLY模式中写,会抛出NonWritableChannelException。如果读取的channel没有开放,此时的读取会抛出NonReadableChannelException。
e.g.