理解java中的mmap理解java中的mmap
jdk中的MappedByteBuffer非常类似linux中的mmap将文件映射到虚拟内存,这样可以利用操作系统自带的虚拟内存实现来
提高io效率, 很多文档中提到这一点,具体大家可以自行测试。
MappedByteBuffer有3种映射模式:
MapMode.READ_ONLY:只读映射
MapMode.READ_WRITE?:读写映射
MapMode.PRIVATE?:copy on write映射,一旦需要改变原有buffer,拷贝一份原来的
本文通过一种测试代码来理解MappedByteBuffer使用MapMode.READ_WRITE以及MapMode.PRIVATE,特别是MAP_MODE.PRIVATE模式?
public class MMapTest { private static FileChannel channel; @BeforeClass public static void runBeforeClass() throws FileNotFoundException {  String path = Resource("/").
getPath();  File file = new File(path);  channel = new RandomAccessFile(file, "rw").getChannel(); } @AfterClass public static void runAfterClass() throws IOException {  channel.close(); } @Before public void runBeforeEveryTest() throws IOException {  ByteBuffer temp = ByteBuffer.allocate(100);  temp.put("12345".getBytes());  temp.flip();  uncate(5);  channel.write(temp); } /**  *  * @author weip.pengw  * @time 2012-3-19 下午02:53:21  * @param buffer  * @throws Exception  */ public static String dumpBuffer(ByteBuffer buffer) throws Exception {  StringBuffer sb = new StringBuffer();  int nulls = 0;  int limit = buffer.limit();  for (int i = 0; i < limit; i++) {  char c = (char) (i);  if (c == '\u0000') {    nulls++;    continue;  }  if (nulls != 0) {    sb.append("|[" + nulls + " nulls]|");    nulls = 0;  }  sb.append(c);  }  String(); } /**  *  * @author weip.pengw  * @throws Exception  * @time 2012-3-19 下午02:45:28  */ @Test public void testCopyOnWrite() throws Exception {  // 产生一个文件,文件跨内存页  ByteBuffer temp = ByteBuffer.allocate(100);  temp.put("This is the file content".getBytes());  temp.flip();  channel.write(temp, 0);  temp.clear();  temp.put("This is more file content".getBytes());  temp.flip();  channel.write(temp, 8192);  // 产生两个MAPFILE  MappedByteBuffer rw = channel.map(FileChannel.MapMode.READ_WRITE, 0,    channel.size());  MappedByteBuffer cow = channel.map(FileChannel.MapMode.PRIVATE, 0,    channel.size());  // 测试之前  assertThat(    dumpBuffer(rw),    is("This is the file content|[8168 nulls]|This is more file content"));  assertThat(    dumpBuffer(cow),    is("This is the file content|[8168 nulls]|This is more file content"));  // 测试step1,修
改rw前几个字节  rw.position(0);  rw.put("RW".getBytes());  rw.force();  assertThat(    dumpBuffer(rw),    is("RWis is the file content|[8168 nulls]|This is more file content"));  assertThat(    dumpBuffer(cow),    is("RWis is the file content|[8168 nulls]|This is more file
content"));  // 测试step2,修改cow前几个字节,触发copy on write  cow.position(0);  cow.put("COW".getBytes());  assertThat(    dumpBuffer(rw),    is("RWis is the file content|[8168 nulls]|This is more file content"));  assertThat(    dumpBuffer(cow),    is("COWs is the file content|[8168 nulls]|This is more file content"));  // 测试step3,修改rw的最后几个字节,cow后面的字节反应了改变  rw.position(8192);  rw.put("RW".getBytes());  rw.force();  assertThat(    dumpBuffer(rw),    is("RWis is the file content|[8168 nulls]|RWis is more file content"));  assertThat(    dumpBuffer(cow),    is("COWs is the file content|[8168 nulls]|RWis is more file content"));  // 测试step4,修改cow的最后几个字节,再次触发copy on write  cow.position(8192);  cow.put("COW".getBytes());  assertThat(    dumpBuffer(rw),    is("RWis is the file content|[8168 nulls]|RWis is more file content"));  assertThat(    dumpBuffer(cow),    is("COWs is the file content|[8168 nulls]|COWs is more file content"));  // 测试step5,再次修改rw的前后几个字节,对cow没有了影响  rw.position(0);  rw.put("RW2".getBytes());  rw.position(8192);  rw.put("RW2".getBytes());  rw.force();  assertThat(    dumpBuffer(rw),    is("RW2s is the file content|[8168 nulls]|RW2s is more file content"));  assertThat(    dumpBuffer(cow),    is("COWs is the file content|[8168 nulls]|COWs is more file content"));  // cleanup  // channel.close(); }
重点看看代码中的测试方法testCopyOnWrite
1)产生一个较大空洞文件(本文操过8k),使得操作系统(代码在ubuntu10.04测试通过)无法在一页能映射该文件(跨内存页),这样才会有测试效果
2)将文件映射到两个MappedByteBuffer实例,一个是MapMode.READ_WRITE模式简称rw,一个是FileChannel.MapMode.PRIVATE模式简称cow
3)  测试之前,两个buff实例内容一致
4)第1步测试修改rw实例,由于没有触发copy on write,所以两个buff实例内容一致
5)  第2步测试修改cow实例的前几个字节,cow的修改只影响它本身,因为它修改的时候实际上重新拷贝了一份
6)第3步测试修改rw实例的后几个字节,居然在cow实例中能看到,之前不是说cow拷贝了一份吗?原因后面说
7)第4步测试修改cow实例的后几个字节,?cow的修改只影响它本身
truncate读8)第5步测试修改rw实例的前后字节,发现都没反映在cow实例中,的确和6)有所不同。
这说明:
一开始没有修改cow,会共用rw的内存,当cow修改了前几个字节,cow会拷贝内存,但明显cow实例是按内存页拷贝的,由于文件较长,?所以只拷贝了前一个部分,前面的是自己的,后面是共享的?当cow修改了后几个字节?,cow才拷贝后面的内存页,这样的话,bw对文件后面的修
改,cow也就看不到了

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。