1.简介
内存映射文件,机器学习读大文件时可用,效率比传统IO要高。
用于内存映射文件的这部分内存,在Java的堆空间以外。
常见nio相关类见《 java NIO》,http://blog.csdn.net/chuchus/article/details/51886586 。
1.1 传统读写
在传统的文件IO中,底层是类似C语言的read()、write()操作 ,操作系统 由当前的【用户态】切换到【内核态】,然后读数据至【OS缓冲区】,再拷贝到【进程的私有地址空间】中去,这样便完成了一次IO操作。
问:为什么要多此一举搞一个内核IO缓冲区把原本只需一次拷贝数据的事情搞成需要2次数据拷贝呢?
答:根据程序访问的局部性原理,这么做是为了减少磁盘的IO操作。当继续访问的文件数据在OS缓冲区时,便直接拷贝数据到进程私有空间,避免了再次的低效率磁盘IO操作。
问:既然如此,JAVA的IO包中为啥还要提供一个 BufferedInputStream 类来作为缓冲区呢?
答:当读取OS内核缓冲区数据的时候,便发起了一次系统调用操作(通过native的C函数调用),而系统调用的代价相对来说是比较高的,涉及到进程用户态和内核态的上下文切换等一系列操作。
BufferedInputStream 会根据情况自动为我们预读更多的字节数据到它自己维护的一个内部字节数组缓冲区中,这样我们便可以减少系统调用次数,从而达到其缓冲区的目的。
1.2 内存映射
内存映射文件和之前说的 标准IO操作最大的不同之处就在于它虽然最终也是要从磁盘读取数据,但是它并不需要将数据读取到OS内核缓冲区,而是直接将进程的用户私有地址空间中的一部分区域与文件对象建立起映射关系,就好像直接从内存中读、写文件一样,速度当然快了。
2.相关类
java.nio.MappedByteBuffer
一个直接的字节缓冲,内容是一个文件的内存映射区域。
MappedByteBuffer java.nio.channels.FileChannel.map(MapMode mode, long position, long size)
将当前文件的一部分直接映射到内存。size为要映射部分的大小。
2.1 映射模式
java.nio.channels.FileChannel.MapMode
映射模式的枚举。
java.nio.channels.FileChannel.MapMode.READ_ONLY
只读。
java.nio.channels.FileChannel.MapMode.READ_WRITE
读写。
java.nio.channels.FileChannel.MapMode.PRIVATE
copy-on-write模式。
专用模式采用的是OS的“写时拷贝”原则,即在没有发生写操作的情况下,多个进程之间都是共享文件的同一块物理内存(进程各自的虚拟地址指向同一片物理地址)。一旦某个进程进行写操作,那么将会把受影响的文件数据单独拷贝一份到进程的私有缓冲区中,不会反映到物理文件中去。
3.例子
1G文件的读写,都在1秒以内。
实际使用中,用完FileChannel后必须将其关闭。