MappedByteBuffer實現(xiàn)MMAP(Memory Mapped Files)技術(內(nèi)存映射)
mmap(Memory Mapped Files),簡單描述其作用就是:將磁盤文件映射到內(nèi)存, 用戶通過修改內(nèi)存就能修改磁盤文件执虹。
它的工作原理是直接利用操作系統(tǒng)的Page來實現(xiàn)文件到物理內(nèi)存的直接映射溅漾。完成映射之后你對物理內(nèi)存的操作會被同步到硬盤上(操作系統(tǒng)在適當?shù)臅r候)荣回。
通過mmap,進程像讀寫硬盤一樣讀寫內(nèi)存(當然是虛擬機內(nèi)存),也不必關心內(nèi)存的大小有虛擬內(nèi)存為我們兜底患亿。使用這種方式可以獲取很大的I/O提升臂拓,省去了用戶空間到內(nèi)核空間復制的開銷贴彼。
mmap也有一個很明顯的缺陷——不可靠,寫到mmap中的數(shù)據(jù)并沒有被真正的寫到硬盤埃儿,操作系統(tǒng)會在程序主動調(diào)用flush的時候才把數(shù)據(jù)真正的寫到硬盤器仗。
benchmark比較:
小數(shù)據(jù)量測試,每次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("執(zhí)行時間:"+(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 個字節(jié)映射到內(nèi)存中
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("執(zhí)行時間:"+(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