MappedByteBuffer实现MMAP(Memory Mapped Files)技术(内存映射)
mmap(Memory Mapped Files),简单描述其作用就是:将磁盘文件映射到内存, 用户通过修改内存就能修改磁盘文件。
它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)。
通过mmap,进程像读写硬盘一样读写内存(当然是虚拟机内存),也不必关心内存的大小有虚拟内存为我们兜底。使用这种方式可以获取很大的I/O提升,省去了用户空间到内核空间复制的开销。
mmap也有一个很明显的缺陷——不可靠,写到mmap中的数据并没有被真正的写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正的写到硬盘。
benchmark比较:
小数据量测试,每次32byte
FileChannel的性能
/*
@author: chenyang
@date 2019/11/10 12:10 AM
*/
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NormalNio {
RandomAccessFile aFile;
FileChannel inChannel;
public NormalNio() throws Exception{
this.aFile = new RandomAccessFile("/Users/chenyang/data/nio-data.txt", "rw");
this.inChannel = aFile.getChannel();
}
public static void main(String[] args) throws Exception{
NormalNio normalNio=new NormalNio();
long start= System.currentTimeMillis();
for(int k=0;k<100;k++) {//100*1024*1024=100m
System.out.println(k);
for (int i = 0; i < 1024; i++) {//1024*1024=1m
for (int j = 0; j < 32; j++) {//1024
normalNio.writeFile();
}
}
}
System.out.println("执行时间:"+(System.currentTimeMillis()-start)/1000);
normalNio.inChannel.close();
}
private void writeFile() throws Exception{
inChannel.position(aFile.length());
String newData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ;
byte[] bytes=newData.getBytes();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.put(bytes);
buf.flip();
while (buf.hasRemaining()) {
inChannel.write(buf);
}
}
}
响应时间:25s
MappedByteBuffer(MMAP)的性能:
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class MappedByteBufferNio {
RandomAccessFile aFile;
FileChannel inChannel;
MappedByteBuffer mappedByteBuffer;
public MappedByteBufferNio() throws Exception{
this.aFile = new RandomAccessFile("/Users/chenyang/data/nio-data.txt", "rw");
this.inChannel = aFile.getChannel();
//将文件的前 100*1024*1024 个字节映射到内存中
this.mappedByteBuffer=inChannel.map(FileChannel.MapMode.READ_WRITE,0,100*1024*1024);
}
public static void main(String[] args) throws Exception{
MappedByteBufferNio mappedByteBufferNio=new MappedByteBufferNio();
long start= System.currentTimeMillis();
for(int k=0;k<100;k++) {//100*1024*1024=100m
System.out.println(k);
for (int i = 0; i < 1024; i++) {//1024*1024=1m
for (int j = 0; j < 32; j++) {//1024
mappedByteBufferNio.writeFile();
}
}
}
System.out.println("执行时间:"+(System.currentTimeMillis()-start)/1000);
mappedByteBufferNio.inChannel.close();
mappedByteBufferNio.aFile.close();
}
private void writeFile() throws Exception{
inChannel.position(aFile.length());
String newData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ;//32 byte
byte[] bytes=newData.getBytes();
mappedByteBuffer.put(bytes);
}
}
响应时间:6s