Netty源码解析之UnpooledHeapByteBuf

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/heroqiang/article/details/81137585

阅读须知

  • Netty版本:4.1.14.Final
  • 文章中使用/* */注释的方法会做深入分析

正文

建议首先阅读Netty源码解析之AbstractByteBuf,UnpooledHeapByteBuf是AbstractByteBuf的子类,它是基于内存的非池化的字节缓冲区,我们首先来看它的主要成员变量:
UnpooledHeapByteBuf:

// 用于内存分配
private final ByteBufAllocator alloc;
// 字节数组缓冲区
byte[] array;
// 用于实现ByteBuf到JDK ByteBuffer的转换
private ByteBuffer tmpNioBuf;

我们在分析AbstractByteBuf的读写操作时看到有一些操作是需要子类实现的,其中读操作readBytes方法中会调用需要子类实现的getBytes方法来完成复制字节到目标数组的操作,我们来看实现:
UnpooledHeapByteBuf:

public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
    // 检查数组下标和容量
    checkDstIndex(index, length, dstIndex, dst.length);
    // 从原数组复制length个字节到目标字节数组中
    System.arraycopy(array, index, dst, dstIndex, length);
    return this;
}

很简单,除了校验之外就是使用JDK的API System.arraycopy来完成复制操作。同样,写操作writeBytes也需要子类实现setBytes方法来完成将字节复制到缓冲区的操作:
UnpooledHeapByteBuf:

public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
    // 检查数组下标和容量
    checkSrcIndex(index, length, srcIndex, src.length);
    // 将指定字节数组从srcIndex下标开始复制length长度到缓冲区中
    System.arraycopy(src, srcIndex, array, index, length);
    return this;
}

与读操作非常相似,只不过是数组复制的方向是相反的。我们在介绍AbstractByteBuf的writeBytes方法时提到,在缓冲区容量不够时是可以动态扩容的,计算过后调整容量的操作是由子类来完成的,我们来看实现:
UnpooledHeapByteBuf:

public ByteBuf capacity(int newCapacity) {
    // 检查缓冲区是否被释放,新的容量不能小于0且新容量不能大于最大容量
    checkNewCapacity(newCapacity);
    int oldCapacity = array.length;
    byte[] oldArray = array;
    // 新容量大于旧容量的情况,直接拷贝和替换旧数组即可
    if (newCapacity > oldCapacity) {
        // 新容量创建新字节数组
        byte[] newArray = allocateArray(newCapacity);
        // 将旧字节数组中的内容拷贝到新数组中
        System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
        // 将数组设置为新数组,将用于软换为JDK ByteBuffer的tmpNioBuf变量置为null
        setArray(newArray);
        // 子类实现释放旧数组操作,默认空实现
        freeArray(oldArray);
    // 新容量小于旧容量的情况,需要考虑读写索引的设置和拷贝的长度
    } else if (newCapacity < oldCapacity) {
        // 新容量创建新字节数组
        byte[] newArray = allocateArray(newCapacity);
        int readerIndex = readerIndex();
        // 读索引小于新容量的情况
        if (readerIndex < newCapacity) {
            int writerIndex = writerIndex();
            if (writerIndex > newCapacity) {
                // 写索引大于新容量,将写索引置为新容量
                writerIndex(writerIndex = newCapacity);
            }
            // 从读索引开始,从旧数组中拷贝写索引减读索引也就是未读的部分到新数组中
            System.arraycopy(oldArray, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
        } else {
            // 这里说明读写索引都不小于新容量,所以直接将读写索引设置为新容量
            setIndex(newCapacity, newCapacity);
        }
        // 将数组设置为新数组,将用于软换为JDK ByteBuffer的tmpNioBuf变量置为null
        setArray(newArray);
        // 子类实现释放旧数组操作,默认空实现
        freeArray(oldArray);
    }
    return this;
}

最后我们来看一下如何转换为JDK的ByteBuffer:
UnpooledHeapByteBuf:

public ByteBuffer nioBuffer(int index, int length) {
    ensureAccessible();
    return ByteBuffer.wrap(array, index, length).slice();
}

很简单,调用JDK NIO提供的API来完成转换JDK ByteBuffer的操作。到这里UnpooledHeapByteBuf的源码分析就完成了。

猜你喜欢

转载自blog.csdn.net/heroqiang/article/details/81137585