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 }
复制代码

 

posted @   会飞的猪仔  阅读(562)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示