Netty源码-ByteBuffer扩容与缩容

Netty源码-ByteBuffer扩容与缩容

AbstractNioByteChannel.read()

public final void read() {
           final ChannelConfig config = config();
           if (shouldBreakReadReady(config)) {
               clearReadPending();
               return;
           }
           final ChannelPipeline pipeline = pipeline();
           final ByteBufAllocator allocator = config.getAllocator();
           final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
           allocHandle.reset(config);

           ByteBuf byteBuf = null;
           boolean close = false;
           try {
               do {
                   //创建ByteBuffer
                   byteBuf = allocHandle.allocate(allocator);
                   allocHandle.lastBytesRead(doReadBytes(byteBuf));
                   if (allocHandle.lastBytesRead() <= 0) {
                       // nothing was read. release the buffer.
                       byteBuf.release();
                       byteBuf = null;
                       close = allocHandle.lastBytesRead() < 0;
                       if (close) {
                           // There is nothing left to read as we received an EOF.
                           readPending = false;
                       }
                       break;
                   }

                   allocHandle.incMessagesRead(1);
                   readPending = false;
                   pipeline.fireChannelRead(byteBuf);
                   byteBuf = null;
               } while (allocHandle.continueReading());

               allocHandle.readComplete();
               pipeline.fireChannelReadComplete();

               if (close) {
                   closeOnRead(pipeline);
               }
           } catch (Throwable t) {
               handleReadException(pipeline, byteBuf, t, close, allocHandle);
           } finally {
               if (!readPending && !config.isAutoRead()) {
                   removeReadOp();
               }
           }
       }
   }

byteBuf = allocHandle.allocate(allocator);如果数据量大就扩充,如果数据量小就缩容

1、这个方法决定了ByteBuf是直接内存还是堆内存
2、创建的ByteBuf是一个自适应的BufferBuf

一、Netty创建ByteBuf创建的是直接内存还是堆内存

DefaultMaxMessagesRecvByteBufAllocator.allocate(ByteBufAllocator alloc)

       //ByteBuf的创建过程
       public ByteBuf allocate(ByteBufAllocator alloc) {
           //alloc.ioBuffer()是创建堆内存的ByteBuf还是直接内存的ByteBuf
           //guess()对ByteBuf进行扩容与缩容
           return alloc.ioBuffer(guess());
       }

AbstractByteBufAllocator.ioBuffer()

 public ByteBuf ioBuffer(int initialCapacity) {
       //一般走if分支创建直接内存的
       if (PlatformDependent.hasUnsafe() || isDirectBufferPooled()) {
           return directBuffer(initialCapacity);
       }
       return heapBuffer(initialCapacity);
   }

二、ByteBuf自适应决定ByteBuf的大小

AdaptiveRecvByteBufAllocator 自适应的核心

   //扩容偏移量
    private static final int INDEX_INCREMENT = 4;
    //减容偏移量
    private static final int INDEX_DECREMENT = 1;
    //这是一个扩容池
    static {
        List<Integer> sizeTable = new ArrayList<Integer>();
        for (int i = 16; i < 512; i += 16) {
         	// 16  32  48 64
            sizeTable.add(i);
        }
        //当超过Interge的最大值这个循环结束
        for (int i = 512; i > 0; i <<= 1) {//<<=1 表示乘以2
            sizeTable.add(i);
        }

        SIZE_TABLE = new int[sizeTable.size()];
        for (int i = 0; i < SIZE_TABLE.length; i ++) {
            SIZE_TABLE[i] = sizeTable.get(i);
        }
    }
    //查询容量池找索引   这个是采用二分查找算法从容量池进行查询
    private static int getSizeTableIndex(final int size) {
        for (int low = 0, high = SIZE_TABLE.length - 1;;) {
            if (high < low) {
                return low;
            }
            if (high == low) {
                return high;
            }

            int mid = low + high >>> 1;
            int a = SIZE_TABLE[mid];
            int b = SIZE_TABLE[mid + 1];
            if (size > b) {
                low = mid + 1;
            } else if (size < a) {
                high = mid - 1;
            } else if (size == a) {
                return mid;
            } else {
                return mid + 1;
            }
        }
    }
 @Override
       public int guess() {
          //每一次结合我们接受的数据,猜测下一次ByteBuf的大小
           return nextReceiveBufferSize;
       }
   public AdaptiveRecvByteBufAllocator(int minimum, int initial, int maximum) {
       checkPositive(minimum, "minimum");
       if (initial < minimum) {
           throw new IllegalArgumentException("initial: " + initial);
       }
       if (maximum < initial) {
           throw new IllegalArgumentException("maximum: " + maximum);
       }

       int minIndex = getSizeTableIndex(minimum);
       if (SIZE_TABLE[minIndex] < minimum) {
           this.minIndex = minIndex + 1;
       } else {
           this.minIndex = minIndex;
       }

       int maxIndex = getSizeTableIndex(maximum);
       if (SIZE_TABLE[maxIndex] > maximum) {
           this.maxIndex = maxIndex - 1;
       } else {
           this.maxIndex = maxIndex;
       }

       this.initial = initial;
   }

扩容减容的实际

public void lastBytesRead(int bytes) {
     //attemptedBytesRead() 表示ByteBuffer的大小  
     //bytes 表示这个写入的ByteBuf大小,如果相等,说明没有读完
     //ByteBuf大小不够,需要进行扩容
        if (bytes == attemptedBytesRead()) {
            //扩容的核心
            record(bytes);
        }
        super.lastBytesRead(bytes);
    }
       

record(bytes);

     //actualReadBytes表示实际读到的ByteBuf大小
      private void record(int actualReadBytes) {
            //INDEX_DECREMENT默认为1 index 表示的是1024的下标
            //SIZE_TABLE[max(0, index - INDEX_DECREMENT)]表示的拿到512
            if (actualReadBytes <= SIZE_TABLE[max(0, index - INDEX_DECREMENT)]) {
                //默认decreaseNow为false
                // 缩容的条件:是两次都不满足的话才缩容
                if (decreaseNow) {
                   //保证缩容的最小值不能小于我们预设的ByteBuf的最小值
                    index = max(index - INDEX_DECREMENT, minIndex);
                    //通过下标取缩容的容量
                    nextReceiveBufferSize = SIZE_TABLE[index];
                    decreaseNow = false;
                } else {
                    decreaseNow = true;
                }
            } else if (actualReadBytes >= nextReceiveBufferSize) {
                //扩容的最大值不能大于我们预设的最大值
                index = min(index + INDEX_INCREMENT, maxIndex);
                ///通过下标取扩容的容量
                nextReceiveBufferSize = SIZE_TABLE[index];
                decreaseNow = false;
            }

二、Unsafe

主要负责read和write底层的实现

线程不安全----------------线程独享
IO操作
 read   NIOByteUnsafe
 write   AbstractUnsafe

在这里插入图片描述

Unsafe()的创建流程,在AbstractChannel

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值