netty5.0源码学习(AdaptiveRecvByteBufAllocator)

    AdaptiveRecvByteBufAllocator是一个用于为接收的数据创建缓冲区的工具类,其特点是能够根据上一次接收数据的大小,来自动调整下一次缓冲区建立时分配的空间大小,避免内存的浪费。下面我们通过源码来看下其实现。

    首先类中定义了一个int型的数组,保存了一些预设的缓冲区大小。

    private static final int[] SIZE_TABLE;

    static {
        List<Integer> sizeTable = new ArrayList<Integer>();
        for (int i = 16; i < 512; i += 16) {
            sizeTable.add(i);
        }

        for (int i = 512; i > 0; i <<= 1) {
            sizeTable.add(i);
        }

        SIZE_TABLE = new int[sizeTable.size()];
        for (int i = 0; i < SIZE_TABLE.length; i ++) {
            SIZE_TABLE[i] = sizeTable.get(i);
        }
    }

    通过静态代码块初始化这个数组,初始化之后数组的长度为53,前32位是16的倍数,从16开始,到512,第33位开始,值是前一位的两倍,最大值为1073741824。每一次分配的缓冲区的大小,都是数组中的某一个值,不是一个随机的值。

    自动调整下一次缓冲区大小的方法是AdaptiveRecvByteBufAllocator的一个内部类HandleImpl实现的。在HandleImpl定义了两个特别的参数:

        private int nextReceiveBufferSize;
        private boolean decreaseNow;

     1、nextReceiveBufferSize:下一次缓冲区分配的大小,自动调整即调整该值的大小

扫描二维码关注公众号,回复: 653759 查看本文章

     2、decreaseNow:是否需要立即减少缓冲区大小

再来看下其调整nextReceiveBufferSize值的方法:

        @Override
        public void record(int actualReadBytes) {
            if (actualReadBytes <= SIZE_TABLE[Math.max(0, index - INDEX_DECREMENT - 1)]) {
                if (decreaseNow) {
                    index = Math.max(index - INDEX_DECREMENT, minIndex);
                    nextReceiveBufferSize = SIZE_TABLE[index];
                    decreaseNow = false;
                } else {
                    decreaseNow = true;
                }
            } else if (actualReadBytes >= nextReceiveBufferSize) {
                index = Math.min(index + INDEX_INCREMENT, maxIndex);
                nextReceiveBufferSize = SIZE_TABLE[index];
                decreaseNow = false;
            }
        }

    方法的参数为一次读取操作中实际读取到的数据的大小,将其与nextReceiveBufferSize进行比较,如果actualReadBytes大于等于nextReceiveBufferSize,则立即更新nextReceiveBufferSize的值,其更新后的值与INDEX_INCREMENT这个参数相关。INDEX_INCREMENT是AdaptiveRecvByteBufAllocator定义的一个常量,值为4,也就是说增大的时候一次性会增大的多一些,已保证下次有足够的空间可以接收数据。还有个最大值maxIndex的限制,该值可以自定义。

    相对于增加缓冲区大小的策略,减小时相对保守一些。与INDEX_INCREMENT对应的,减小时也有一个影响参数INDEX_DECREMENT,值为1,将actualReadBytes与当前值前INDEX_DECREMENT+1个进行比较,如果小于,则继续判断,否则则不调整,留有一定的空余。

   

    可以看到,在小于的情况下,也不会立马就调整nextReceiveBufferSize的大小,而是先把decreaseNow置为true,如果下一次仍然小于,才会减少nextReceiveBufferSize的大小。

    总的来说,往大调较为宽松,往小调比较谨慎,以空间换效率,保证有足够的空间来接收读取的数据。

猜你喜欢

转载自jimmy1123.iteye.com/blog/2024236