zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    排序算法<No.3>【桶排序】
    排序算法<No.2>【快速排序】
    排序算法<No.1> 【计数排序】
    排序问题思考(要求时间和空间复杂度尽可能的低)【Part 1】
    elasticsearch【cat API,系统数据】指令汇总
    netty研究【1】:编译源代码
    D3树状图给指定特性的边特别显示颜色
    zabbix3.0安装之图形界面显示异常【server】
    计算一维组合数的java实现
    zabbix3.0安装【server】
  • 原文地址:https://www.cnblogs.com/ouhaitao/p/12876128.html
Copyright © 2011-2022 走看看