ByteBuf源码学习(仅供自己研究)

一、ByteBuf的主要类继承关系:

ByteBuf主要功能类的继承关系

二、ByteBuf容量动态扩展:

ByteBuf允许使用者指定最大容量,在容量范围内可以先分配较小的初始容量,如果不够,可以动态扩展,以达到功能和性能的最优组合。

动态扩容的核心方法就是AbstractByteBufAllocator的**calculateNewCapacity()**方法,该方法入参minNewCapacity=writerIndex + minWritableBytes,为写索引加上当前待写入的长度,表示当前写入时所需的最小容量,maxCapacity为缓存能分配的最大容量

扩容时,设置了阀值threshold=4M(也称步进值):

扩容策略:当所需内存比较小的时候,采用倍增策略,当所需内存较大时,采用步进策略,比如所需10M,进行扩容时,若采用倍增:10*2=20M,则浪费了10M,但是步进策略后为14M,减少了内存浪费。

  • 当所需最小容量大于步进值时:
    如果当前所需最小容量minNewCapacity+步进值大于最大容量,那么就返回最大容量maxCapacity,如果小于最大容量,就以4M进行步进
  • 当所需最小容量小于步进值时:
    扩容的容量newCapacity以初始值64开始,以乘2递增,直到扩容的容量newCapacity大于等于当前写入时所需的最小容量。
@Override
public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
    if (minNewCapacity < 0) {
        throw new IllegalArgumentException("minNewCapacity: " + minNewCapacity + " (expectd: 0+)");
    }
    if (minNewCapacity > maxCapacity) {
        throw new IllegalArgumentException(String.format(
                "minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
                minNewCapacity, maxCapacity));
    }
    final int threshold = 1048576 * 4; // 4 MiB page
    
    if (minNewCapacity == threshold) {
        return threshold;
    }
    // 如果当前写入需要的最小容量超过了阀值,就以阀值进行步进
    if (minNewCapacity > threshold) {
        int newCapacity = minNewCapacity / threshold * threshold;
        if (newCapacity > maxCapacity - threshold) {  // 如果以阀值进行步进,超过了最大容量,就直接返回最大容量
            newCapacity = maxCapacity;
        } else {
            newCapacity += threshold;  //否则新容量就是当前所需最小容量加上阀值
        }
        return newCapacity;
    }
    // 以初始值为64开始,每次乘2,进行递增
    int newCapacity = 64;
    while (newCapacity < minNewCapacity) {
        newCapacity <<= 1;
    }
    
    return Math.min(newCapacity, maxCapacity);
}

三、ByteBuf相关方法:

1、readBytes:
AbstractByteBuf中实现了父类的readBytes方法,但是readBytes方法调用的getBytes方法是交由子类去实现

public abstract ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length);
对于Heap 类型的ByteBuf,数据存入byte数组,每次读取的时候,会进行数组复制:其getByte方法如下:

@Override
public final ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
    checkDstIndex(index, length, dstIndex, dst.length);
    System.arraycopy(memory, idx(index), dst, dstIndex, length);
    return this;
}

数组复制调用的是java native 方法:System.arraycopy(src, srcPos, dst, dstIndex, length)速度非常快,PS: src 源数组,srcPos源数组开始复制的位置,dst目的数组,dstIndex数组复制的位置,length复制内容长度

2、discardReadBytes:
该方法是丢弃ByteBuf中已读取的字节,调用setBytes方法,将readerIndex与writerIndex 之间未读取的数据,复制到缓冲区的起始位置。
setBytes(0, this, readerIndex, writerIndex - readerIndex);
并且读索引readerIndex调整到起始位置0,写索引位置writerIndex为写索引位置减去之前读索引位置。
并且要调整markedReaderIndex,markedWriterIndex的位置,如果markedReaderIndex,markedWriterIndex小于需要的减少量decrement=readerIndex,就置为0,如果大于,则将值更新为减去decrement后的值。

四、ByteBuf引用计数器AbstractReferenceCountedByteBuf:

该类中重要成员变量参数:

【netty5 与netty4不同,多了REFTCNT_FIELD_OFFSET字段:用于标识refCnt在AbstractReferenceCountedByteBuf对象中内存地址】

private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> refCntUpdater;   //通过AtomicIntegerFieldUpdater来对 refCnt字段原子性更新
private volatile int refCnt = 1;    // 用于跟踪对象的引用次数

引用计数refCnt增加:

private ByteBuf retain0(int increment) {   //  // 通常decrement 为1
    for (;;) {
        int refCnt = this.refCnt;
        final int nextCnt = refCnt + increment;
        
        if (nextCnt <= increment) {           
            throw new IllegalReferenceCountException(refCnt, increment);  // 这种情况下,说明refCnt 为0,nextCnt 才会等于increment
        }
        if (refCntUpdater.compareAndSet(this, refCnt, nextCnt)) {   // 通过AtomicIntegerFieldUpdater 的CAS操作,来更新引用计数refCnt 
            break;
        }
    }
    return this;
}

引用计数释放:

private boolean release0(int decrement) {   // 通常decrement 为1
    for (;;) {
        int refCnt = this.refCnt;
        if (refCnt < decrement) {
            throw new IllegalReferenceCountException(refCnt, -decrement);
        }

        if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) { // 原子更新引用计数
            if (refCnt == decrement) {     // 注意当refCnt =1时,表明申请和释放相等,对象不可达,那么该对象需要被释放回收
                deallocate();                  // 对象释放方法交由子类实现,因为父类不清楚子类申请的字节缓冲是堆内的内存,还是堆外内存
                return true;
            }
            return false;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值