深入探秘 Netty、Kafka 中的零拷贝技术!( 二 )

主要通过 FileChannel 提供的 map() 来实现映射,map() 方法如下:
    public abstract MappedByteBuffer map(MapMode mode,                                         long position, long size)        throws IOException;分别提供了三个参数,MapMode,Position 和 Size,分别表示:

  • MapMode:映射的模式,可选项包括:READ_ONLY,READ_WRITE,PRIVATE 。
  • Position:从哪个位置开始映射,字节数的位置 。
  • Size:从 Position 开始向后多少个字节 。
重点看一下 MapMode,前两个分别表示只读和可读可写,当然请求的映射模式受到 Filechannel 对象的访问权限限制,如果在一个没有读权限的文件上启用 READ_ONLY,将抛出 NonReadableChannelException 。
PRIVATE 模式表示写时拷贝的映射,意味着通过 put() 方法所做的任何修改都会导致产生一个私有的数据拷贝并且该拷贝中的数据只有 MappedByteBuffer 实例可以看到 。
该过程不会对底层文件做任何修改,而且一旦缓冲区被施以垃圾收集动作(garbage collected),那些修改都会丢失 。
大致浏览一下 map() 方法的源码:
    public MappedByteBuffer map(MapMode mode, long position, long size)        throws IOException    {            ...省略...            int pagePosition = (int)(position % allocationGranularity);            long mapPosition = position - pagePosition;            long mapSize = size + pagePosition;            try {                // If no exception was thrown from map0, the address is valid                addr = map0(imode, mapPosition, mapSize);            } catch (OutOfMemoryError x) {                // An OutOfMemoryError may indicate that we've exhausted memory                // so force gc and re-attempt map                System.gc();                try {                    Thread.sleep(100);                } catch (InterruptedException y) {                    Thread.currentThread().interrupt();                }                try {                    addr = map0(imode, mapPosition, mapSize);                } catch (OutOfMemoryError y) {                    // After a second OOME, fail                    throw new IOException("Map failed", y);                }            }            // On windows, and potentially other platforms, we need an open            // file descriptor for some mapping operations.            FileDescriptor mfd;            try {                mfd = nd.duplicateForMapping(fd);            } catch (IOException ioe) {                unmap0(addr, mapSize);                throw ioe;            }            assert (IOStatus.checkAll(addr));            assert (addr % allocationGranularity == 0);            int isize = (int)size;            Unmapper um = new Unmapper(addr, mapSize, isize, mfd);            if ((!writable) || (imode == MAP_RO)) {                return Util.newMappedByteBufferR(isize,                                                 addr + pagePosition,                                                 mfd,                                                 um);            } else {                return Util.newMappedByteBuffer(isize,                                                addr + pagePosition,                                                mfd,                                                um);            }     }


推荐阅读