• AdaptiveRecvByteBufAllocator解析


    看官方说法,是一个能根据以往接受的消息进行计算,动态调整内存,利用CPU资源来换取内存资源,具体的实现策略如下:根据之前Channel接收到的数据包大小进行计算,如果连续填充满接收缓冲区的可写空间,则动态扩展容量。如果连续2次接收到的数据包都小于指定值,则收缩当前的容量,以节约内存。具体使用时,代码如下:
    option(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator(DEFAULT_MINIMUM,DEFAULT_INITIAL,DEFAULT_MAXIMUM))或者option(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator())

    接下来看源码:

      1 public class AdaptiveRecvByteBufAllocator extends DefaultMaxMessagesRecvByteBufAllocator {
      2     //接收缓冲区最小长度下限
      3     static final int DEFAULT_MINIMUM = 64;
      4     //接收缓冲区初始化
      5     static final int DEFAULT_INITIAL = 2048;
      6     //接收缓冲区最大长度上限
      7     static final int DEFAULT_MAXIMUM = 65536;
      8     //扩容增长量
      9     private static final int INDEX_INCREMENT = 4;
     10     //扩容减少量
     11     private static final int INDEX_DECREMENT = 1;
     12     private static final int[] SIZE_TABLE;
     13     /** @deprecated */
     14     @Deprecated
     15     public static final AdaptiveRecvByteBufAllocator DEFAULT;
     16     private final int minIndex;
     17     private final int maxIndex;
     18     private final int initial;
     19     //入参是一个大小,然后利用二分查找法对该数组进行size的定位,目标是为了找出该size值在数组中的下标位置,主要是为了初始化minIndex、maxIndex这两个参数
     20     private static int getSizeTableIndex(int size) {
     21         int low = 0;
     22         int high = SIZE_TABLE.length - 1;
     23 
     24         while(high >= low) {
     25             if (high == low) {
     26                 return high;
     27             }
     28 
     29             int mid = low + high >>> 1;
     30             int a = SIZE_TABLE[mid];
     31             int b = SIZE_TABLE[mid + 1];
     32             if (size > b) {
     33                 low = mid + 1;
     34             } else {
     35                 if (size >= a) {
     36                     if (size == a) {
     37                         return mid;
     38                     }
     39 
     40                     return mid + 1;
     41                 }
     42 
     43                 high = mid - 1;
     44             }
     45         }
     46 
     47         return low;
     48     }
     49 
     50     public AdaptiveRecvByteBufAllocator() {
     51         this(64, 2048, 65536);
     52     }
     53 
     54     public AdaptiveRecvByteBufAllocator(int minimum, int initial, int maximum) {
     55         ObjectUtil.checkPositive(minimum, "minimum");
     56         //minimum不能大于初始化长度initial,初始化长度initial不能超过maximum
     57         if (initial < minimum) {
     58             throw new IllegalArgumentException("initial: " + initial);
     59         } else if (maximum < initial) {
     60             throw new IllegalArgumentException("maximum: " + maximum);
     61         } else {
     62             int minIndex = getSizeTableIndex(minimum);
     63             if (SIZE_TABLE[minIndex] < minimum) {
     64                 this.minIndex = minIndex + 1;
     65             } else {
     66                 this.minIndex = minIndex;
     67             }
     68 
     69             int maxIndex = getSizeTableIndex(maximum);
     70             if (SIZE_TABLE[maxIndex] > maximum) {
     71                 this.maxIndex = maxIndex - 1;
     72             } else {
     73                 this.maxIndex = maxIndex;
     74             }
     75 
     76             this.initial = initial;
     77         }
     78     }
     79 
     80     public Handle newHandle() {
     81         return new AdaptiveRecvByteBufAllocator.HandleImpl(this.minIndex, this.maxIndex, this.initial);
     82     }
     83 
     84     public AdaptiveRecvByteBufAllocator respectMaybeMoreData(boolean respectMaybeMoreData) {
     85         super.respectMaybeMoreData(respectMaybeMoreData);
     86         return this;
     87     }
     88     /*
     89     分配了一个int类型的数组,并进行该数组的初始化处理,从实现来看,该数组的长度是53,前32位是16的倍数,value值是从16开始,到512;从第33位开始,值是前一位的两倍,即从1024、2048、到最大值1073741824
     90     */
     91     static {
     92         List<Integer> sizeTable = new ArrayList();
     93 
     94         int i;
     95         for(i = 16; i < 512; i += 16) {
     96             sizeTable.add(i);
     97         }
     98 
     99         for(i = 512; i > 0; i <<= 1) {
    100             sizeTable.add(i);
    101         }
    102 
    103         SIZE_TABLE = new int[sizeTable.size()];
    104 
    105         for(i = 0; i < SIZE_TABLE.length; ++i) {
    106             SIZE_TABLE[i] = (Integer)sizeTable.get(i);
    107         }
    108 
    109         DEFAULT = new AdaptiveRecvByteBufAllocator();
    110     }
    111 
    112     private final class HandleImpl extends MaxMessageHandle {
    113         private final int minIndex;
    114         private final int maxIndex;
    115         private int index;
            //每次调容最关键的参数
    116 private int nextReceiveBufferSize; 117 private boolean decreaseNow; 118 119 HandleImpl(int minIndex, int maxIndex, int initial) { 120 super(AdaptiveRecvByteBufAllocator.this); 121 this.minIndex = minIndex; 122 this.maxIndex = maxIndex;
             //用initial获取一开始初始化缓冲的下标,在根据SIZE_TABLE查找应分配的BufferSize。
    123 this.index = AdaptiveRecvByteBufAllocator.getSizeTableIndex(initial); 124 this.nextReceiveBufferSize = AdaptiveRecvByteBufAllocator.SIZE_TABLE[this.index]; 125 } 126 127 public void lastBytesRead(int bytes) { 128 if (bytes == this.attemptedBytesRead()) { 129 this.record(bytes); 130 } 131 132 super.lastBytesRead(bytes); 133 } 134 135 public int guess() { 136 return this.nextReceiveBufferSize; 137 } 138 /* 139 140 该方法的参数是一次读取操作中实际读取到的数据大小,将其与nextReceiveBufferSize 进行比较,如果实际字节数actualReadBytes大于等于该值,则立即更新nextReceiveBufferSize ,其更新后的值与INDEX_INCREMENT有关。INDEX_INCREMENT为默认常量,值为4。也就是说在扩容时会一次性增大多一些,以保证下次有足够空间可以接收数据。而相对扩容的策略,缩容策略则实际保守些,常量为INDEX_INCREMENT,值为1,同样也是进行对比, 但不同的是,若实际字节小于所用nextReceiveBufferSize,并不会立马进行大小调整,而是先把 decreaseNow 设置为true,如果下次仍然小于,则才会减少nextReceiveBufferSize的大小 141 */ 142 private void record(int actualReadBytes) { 143 if (actualReadBytes <= AdaptiveRecvByteBufAllocator.SIZE_TABLE[Math.max(0, this.index - 1)]) { 144 if (this.decreaseNow) { 145 this.index = Math.max(this.index - 1, this.minIndex); 146 this.nextReceiveBufferSize = AdaptiveRecvByteBufAllocator.SIZE_TABLE[this.index]; 147 this.decreaseNow = false; 148 } else { 149 this.decreaseNow = true; 150 } 151 } else if (actualReadBytes >= this.nextReceiveBufferSize) { 152 this.index = Math.min(this.index + 4, this.maxIndex); 153 this.nextReceiveBufferSize = AdaptiveRecvByteBufAllocator.SIZE_TABLE[this.index]; 154 this.decreaseNow = false; 155 } 156 157 } 158 159 public void readComplete() { 160 this.record(this.totalBytesRead()); 161 } 162 } 163 }
  • 相关阅读:
    Python实现以不同分辨率分类视频
    JPA 的增删改查方法
    JPA 中 find() 和 getReference() 的区别
    (三)JPA工具类
    (二)JPA实体类主键生成策略
    (一)配置JPA的开发环境
    自定义视图和自定义视图解析器
    view-controller
    RedirectAttributes 的使用
    SpringMVC视图解析中的 forward: 与 redirect: 前缀
  • 原文地址:https://www.cnblogs.com/huifeidezhuzai/p/16243557.html
Copyright © 2020-2023  润新知