Linux中mmap技术
一、使用MMAP(Memory Mapped Files)
什么是MMAP(Memory Mapped Files)
MMAP将文件直接映射到用户态的内存地址,这样对文件的操作不再是write/read,而是直接对内存地址的操作。
使用内存映射的方式进行文件读写,而不是传统的IO操作,可以大大减少文件读写系统调用的次数,提升了IO的性能。
内存映射文件的一个关键优势是操作系统负责真正的读写,即使你的程序在刚刚写入内存后就挂了,操作系统仍然会将内存中的数据写入文件系统。另外一个更突出的优势是共享内存,内存映射文件可以被多个进程同时访问,起到一种低时延共享内存的作用。
使用内存映射文件来持久化数据,可以构建高性能Java应用。
传统的文件访问:
系统调用打开文件,获取文件描述符
使用read write 系统调用进行IO
系统调用关闭文件
这种方式是非常低效的, 每一次I/O操作都需要一次系统调用。 另外, 如果若干个进程访问同一个文件, 每个进程都要在自己的地址空间维护一个副本, 浪费了内存空间。
内存映射的方式:
打开文件,得到文件描述符。
获取文件大小
把文件映射成虚拟内存(mmap)
通过对内存的读写来实现对文件的读写(memset或memcpy)
卸载映射
关闭文件
首先建立好虚拟内存和磁盘文件之间的映射(mmap系统调用),当进程访问页面时产生一个缺页中断,内核将页面读入内存(也就是说把磁盘上的文件拷贝到内存中),并且更新页表指向该页面。
所有进程共享同一物理内存,物理内存中可以只存储一份数据,不同的进程只需要把自己的虚拟内存映射过去就可以了,这种方式非常方便于同一副本的共享,节省内存。
经过内存映射之后,文件内的数据就可以用内存读/写指令来访问,而不是用Read和Write这样的I/O系统函数,从而提高了文件存取速度。
二、Java 支持
Java中的java.nio包支持内存映射文件,可以使用java.nio.MappedByteBuffer来读写内存。
三、示例&测试
1 | public static void writeFileWithMmap(String fileName, byte[] data) throws IOException { |
1 | public static void writeFileWithMmap(String fileName, byte[] data) throws IOException { |
四、测试结论
1 | write consume: 2453ms |