Netty ByteBuf分析

本文深入剖析了Netty中的ByteBuf,它弥补了Java原生Buffer的不足。ByteBuf包含读写索引,分为已读区、未读区和可写区。它支持堆缓冲区、直接内存和池缓冲区,利用ByteBuf可以实现零拷贝。文章详细介绍了ByteBuf的实现,包括其内部结构、操作方法,如设置和恢复读写索引、丢弃已读数据、确保写入空间等,以及不同类型的ByteBuf实现,如堆缓冲区和直接内存缓冲区。
摘要由CSDN通过智能技术生成

看完的给提点建议


netty 封装了java自带的 buffer,因为buffer上的一些缺现

netty4.0


byteBuf的指针


readerIndex:读索引

writerindex:写索引


这张图里还缺少一个起始位0,和最大位maxCapacity

0到readerIndex为已读区,

readerIndex到writerindex为未读区

writerindex到maxCapacity为可写区


看完后总结关于ByteBuf的实现,先总结束一下

ByteBuf其实就是封装 了byte数组或ByteBuffer,为自己增加了一个读写索引。

ByteBuf的零拷贝,就是直接使用byte数组或ByteBuffer,将多个byte数组或ByteBuf组装成一个不需要拷贝,只需要将其封装 成CompositeByteBuf(聚合),每个数组都是单独存在,下面有具体看代码

ByteBuf的堆缓冲区使用byte数组实现

ByteBuf的直接内存使用nio提供的ByteBuffer实现

由于堆缓冲和直接内存都是单独存在,每次都需要创建新的影响性能,还提供了池缓冲区,由一个chunk管理,每次创建通过Recycler抽象类创建 

还有一个UnpooledUnsafeDirectByteBuf,这个是使用内存地指操 作的。具体的没肿么看。里面用的都是unsafe.


下面撸代码


分析一下Netty的byteBuf



一陀。我的天。一个个分析吧.

一、AbstractByteBuf继承了ByteBuf


常量

    int readerIndex;     //读索引
    int writerIndex;     //写索引
    private int markedReaderIndex; // 类似bytebuffer中的mark 用于恢复读索引位
    private int markedWriterIndex;  // 同上恢复写索引位置
    private int maxCapacity;  //缓冲区最大值
   private SwappedByteBuf swappedBuf;//返回一个带排序的

//构造方法传入缓冲区最大长度

 protected AbstractByteBuf(int maxCapacity) {
        if (maxCapacity < 0) {
            throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
        }
        this.maxCapacity = maxCapacity;
    }

//将读写索引设置 为0

@Override
    public ByteBuf clear() {
        readerIndex = writerIndex = 0;
        return this;
    }

//是否可读可写,都是通过索引进行判断

@Override
    public boolean isReadable() {
        return writerIndex > readerIndex;
    }


    @Override
    public boolean isReadable(int numBytes) {
        return writerIndex - readerIndex >= numBytes;
    }


    @Override
    public boolean isWritable() {
        return capacity() > writerIndex;
    }


    @Override
    public boolean isWritable(int numBytes) {
        return capacity() - writerIndex >= numBytes;
    }

//下面四个方法,mark开头备份当前读写索引位置 ,reset开头,将读写索引恢复到备份时索引,主要用于回滚

@Override
    public ByteBuf markReaderIndex() {
        markedReaderIndex = readerIndex;
        return this;
    }


    @Override
    public ByteBuf resetReaderIndex() {
        readerIndex(markedReaderIndex);
        return this;
    }


    @Override
    public ByteBuf markWriterIndex() {
        markedWriterIndex = writerIndex;
        return this;
    }


    @Override
    public ByteBuf resetWriterIndex() {
        writerIndex = markedWriterIndex;
        return this;
    }


//丢弃0到readerIndex之间的已读数据

@Override
    public ByteBuf discardReadBytes() {
        ensureAccessible(); //验证缓冲区是否被释放
        if (readerIndex == 0) {//如果读索引为0则直接回返
            return this;
        }


        if (readerIndex != writerIndex) {//判断读索引与写索引是否一至
            setBytes(0, this, readerIndex, writerIndex - readerIndex);//由子类实现,,这里应该是从读索引位置 读取到写索引的数据,向前移,具体看子类
            writerIndex -= readerIndex;//重置 写索引
            adjustMarkers(readerIndex);//重置 备份的的读写索引
            readerIndex = 0;//读索引设置 为0
        } else {
            adjustMarkers(readerIndex);
            writerIndex = readerIndex = 0;//读写索引设置 为0
        }
        return this;
    }

//类似于上面丢弃已读数据,区别读索引必须大于等于可用空间除以2,才会进行丢弃

 @Override
    public ByteBuf discardSomeReadBytes() {
        ensureAccessible();
        if (readerIndex == 0) {
            return this;
        }


        if (readerIndex == writerIndex) {
            adjustMarkers(readerIndex);
            writerIndex = readerIndex = 0;
            return this;
        }


        if (readerIndex >= capacity() >>> 1) {//判断读索引是否大余等于可用空间除以2,如果大于则丢弃已读的缓冲区
            setBytes(0, this, readerIndex, writerIndex - readerIndex);
            writerIndex -= readerIndex;
            adjustMarkers(readerIndex);
            readerIndex = 0;
        }
        return this;
    }


//重新设置 备份的读写索引,,参数decrement理解为当前读引位置 

 protected final void adjustMarkers(int decrement) {
        int markedReaderIndex = this.markedReaderIndex;
        if (markedReaderIndex <= decrement) {//备份的读索引小于等于当前索引执行
            this.markedReaderIndex = 0;//备份读索引设为0
            int markedWriterIndex = this.markedWriterIndex;//
            if (markedWriterIndex <= decrement) {//判断写索引是否小于等于当前读索引
                this.markedWriterIndex = 0;
            } else {
                this.markedWriterIndex = markedWriterIndex - decrement;//如果不小于的话。备份写索引减去当前读索引
            }
        } else {

//备份的读写索引同时减去当前的读索引,生成新的位置 
            this.markedReaderIndex = markedReaderIndex - decrement;
            markedWriterIndex -= decrement;
        }
    }


//参数:可写的字节长度,,,,验证是否允许长度写入

@Override
    public ByteBuf ensureWritable(int minWritableBytes) {
        if (minWritableBytes < 0) {
            throw new IllegalArgumentException(String.format(
                    "minWritableBytes: %d (expected: >= 0)", minWritableBytes));
        }
        ensureWritable0(minWritableBytes);//主要这个方法
        return this;
    }

final void ensureWritable0(int minWritableBytes) {
        ensureAccessible();//验证该 缓冲区是否还有引用
        if (minWritableBytes <= writableBytes()) {
            return;
        }


        if (minWritableBytes > maxCapacity - writerIndex) {//验证需要写入的长度是否大于当前可写入的长度(可写的长度-读索引位置 )
            throw new IndexOutOfBoundsException(String.format(
                    "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值