面试被问到“零拷贝”?我一脸懵逼!
来源:https://my.oschina.net/OutOfMemory/blog/3034514
前言
从字面意思理解就是数据不需要来回的拷贝,大大提升了系统的性能;这个词我们也经常在java nio,netty,kafka,RocketMQ等框架中听到,经常作为其提升性能的一大亮点;下面从I/O的几个概念开始,进而在分析零拷贝。
I/O概念
1.缓冲区
public class MappedByteBufferTest { public static void main(String[] args) throws Exception { File file = new File("D://db.txt"); long len = file.length(); byte[] ds = new byte[(int) len]; MappedByteBuffer mappedByteBuffer = new FileInputStream(file).getChannel().map(FileChannel.MapMode.READ_ONLY, 0, len); for (int offset = 0; offset < len; offset++) { byte b = mappedByteBuffer.get(); ds[offset] = b; } Scanner scan = new Scanner(new ByteArrayInputStream(ds)).useDelimiter(" "); while (scan.hasNext()) { System.out.print(scan.next() + " "); } } } public abstract MappedByteBuffer map(MapMode mode, long position, long size) throws IOException; 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); } }ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(100);public class ChannelTransfer { public static void main(String[] argv) throws Exception { String files[]=new String[1]; files[0]="D://db.txt"; catFiles(Channels.newChannel(System.out), files); }
private static void catFiles(WritableByteChannel target, String[] files) throws Exception { for (int i = 0; i < files.length; i++) { FileInputStream fis = new FileInputStream(files[i]); FileChannel channel = fis.getChannel(); channel.transferTo(0, channel.size(), target); channel.close(); fis.close(); } }} public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException;public class CompositeChannelBuffer extends AbstractChannelBuffer {
private final ByteOrder order; private ChannelBuffer[] components; private int[] indices; private int lastAccessedComponentId; private final boolean gathering; public byte getByte(int index) { int componentId = componentId(index); return components[componentId].getByte(index - indices[componentId]); } ...省略...