netty零拷贝

1. 使用DirectBuffer

  以下是NioEventLoop#processSelectedKey方法的部分代码

1 if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
2     unsafe.read();
3     if (!ch.isOpen()) {
4         // Connection already closed - no need to handle write.
5         return;
6     }
7 }

  unsafe.read()方法对应AbstractNioByteChannel.NioByteUnsafe#read方法。

  该方法的部分代码如下

1 RecvByteBufAllocator.Handle allocHandle = this.allocHandle;
2 if (allocHandle == null) {
3     this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle();
4 }
5 // 省略部分代码...
6 byteBuf = allocator.ioBuffer(byteBufCapacity);
7 int writable = byteBuf.writableBytes();
8 int localReadAmount = doReadBytes(byteBuf);

  在执行读操作之前先获取了一个RecvByteBufAllocator.Handle的对象,该对象是用于获取ByteBuf的工具类,可以跟踪代码看到这个工具类是AdaptiveRecvByteBufAllocator#HandleImpl。

  再看工具类的申请byteBuf的方法ioBuffer

1 public ByteBuf ioBuffer(int initialCapacity) {
2     if (PlatformDependent.hasUnsafe()) {
3         return directBuffer(initialCapacity);
4     }
5     return heapBuffer(initialCapacity);
6 }

  这里默认会返回directBuffer。

  获取到byteBuf之后就可以调用doReadBytes方法将数据包读取到byteBuf中。该方法最终会调用到java的socketChannel的read方法,该方法调用IOUtil#read方法来读取数据,来看下该方法的部分代码

1 if (dst instanceof DirectBuffer)
2     return readIntoNativeBuffer(fd, dst, position, nd);
3 // Substitute a native buffer
4 ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());

  在开始读取之前先判断byteBuffer是不是DirectBuffer,如果是则直接读取数据,否则需要将byteBuffer拷贝到JVM内存中。

  从以上流程可知netty使用directBuf来实现零拷贝。

2. 使用CompositeByteBuf

  该类其实就是一个装饰器,将多个byteBuf组装成逻辑上的一个byteBuf,并不存在内存拷贝。详细介绍https://segmentfault.com/a/1190000007560884

3. 使用FileRegion

  该类是netty的文件传输类,实际上底层是使用的java的NIO提供的transferTo方法将一个channel的数据传输到另一个channel中。

ps:需要特别注意的是,netty的零拷贝与系统的零拷贝是不同概念,系统层面的零拷贝指的是避免在用户态与内核态间拷贝数据;而netty作为一个应用程序,它只存在于用户态,即使是申请的directBuffer同样是位于用户态。
  socketChannel的数据位于内核态,要把该数据读取到用户态必定会拷贝一次,如果使用directBuffer,则可以直接把数据读取到buffer;如果使用heapBuff,则需要先创建一个directBuffer,然后读取到directBuffer中,然后再从directBuffer读取到目标heapBuff。

深入了解java directBuffer:

https://www.zhihu.com/question/57374068/answer/152691891

netty的directBuf与heapBuf的区别:

https://my.oschina.net/u/2381372/blog/1476329

原文地址:https://www.cnblogs.com/ouhaitao/p/12876128.html