Netty入门P6

ByteBuf结构

ByteBuf结构示意图:
ByteBuf示意图

根据示意图可以看出:

  1. ByteBuf是一个字节容器,容器整体可分为四个部分:
    1. 已废弃字节部分,此部分的数据是无效的;
    2. 可读字节部分,此部分的数据是ByteBuf的主体数据,从ByteBuf读取的数据来自此部分;
    3. 可写字节部分,所有向ByteBuf写入的数据都会保存在此部分;
    4. 剩余可扩容字节部分,表示ByteBuf还能扩容多少字节;
  2. 其中前三部分是通过两个指针来划分开的,一个是读指针(readerIndex)另一个是写指针(writerIndex),还有一个变量容量(capacity)用以表示ByteBuf底层内存的总量;
  3. 从ByteBuf中往外读取数据时,readerIndex自增1,ByteBuf总共有(readerIndex - writerIndex)个可读字节,因此readerIndex 与readerIndex相等时是无法读取数据的;
  4. 写数据是从writerIndex指向的部分开始写入,每写入一个字节writerIndex自增1,直到与capacity相等时表示ByteBuf已经不可写入;
  5. maxCapacity表示ByteBuffer可扩容到的字节上限,当向ByteBuf中写入数据时,如果容量不够则会进行扩容,当capacity比maxCapacity大时则会报错;

与容量相关的API

常见API如下:

API名称功能介绍
capacity()表示ByteBuf底层占用了多少字节内存;
maxCapacity()表示ByteBuf底层能够占用的最大字节数;
readableBytes表示当前ByteBuf可读的字节数,与(writerIndex - readerIndex)等值;
isReadable()如果writableIndex与readableIndex等值,则不可读,isReadable返回fales;
writableBytes()表示ByteBuf当前可写的字节数,等值于capacity - writerIndex;
isWriterable()如果capacity与writerIndex等值,则为不可写状态,isWritable()返回false;
maxwritableBytes()maxwritableBytes()表示可写的最大字节数,等值于maxCapacity - writerIndex;

与指针相关的API

常见API如下:

API名称功能介绍
readerIndex()表示获取当前的读指针;
readerIndex(int)表示设置读指针的位置;
writerIndex()表示获取当前的写指针;
writerIndex(int)表示设置写指针的位置;
markReaderIndex()表示保存读指针的位置;
reasetReaderIndex()表示将当前读指针的位置恢复到上次保存的位置;
markWriterIndex()表示保存写指针的位置;
resetWriterIndex()表示将当前写指针的位置恢复到上次保存的位置;

读写API

常见API如下:

API名称功能介绍
writeBytes(byte[])表示将参数数据写入到ByteBuf中;
通常情况下参数数组与可写入数据大小相同;
readerBytes(byte[])表示将ByteBuf中的数据写入到参数数组中;
通常情况下参数数组与可读数据长度相同;
writeByte(byte)表示写入一个Byte到ByteBuf中;
与之类似的还有writeLong()、writeDouble()等等;
readByte(byte)表示从ByteBuf读取一个Byte数据;
与之类似的还有readLong()、readDouble()等;
release()表示使得引用计数+1;
retain()表示使得引用计数-1;
slice()返回一个ByteBuf,其中的数据为原ByteBuf从readerIndex至writerIndex之间的数据,且返回的ByteBuf的maxCapacity为原ByteBuf的readableBytes();
向返回的ByteBuf与原有ByteBuf内存共享;
不影响原有ByteBuf的指针;
不会影响原有ByteBuf的引用数;
duplicate()返回一个ByteBuf,返回的ByteBuf与原ByteBuf的数据、指针相同;
向返回的ByteBuf与原有ByteBuf内存共享;
不影响原有ByteBuf的指针;
不会影响原有ByteBuf的引用数;
copy()返回一个ByteBuf,返回的ByteBuf与原ByteBuf完全相同,向返回的ByteBuf写入数据并不会影响原有ByteBuf;
不影响原有ByteBuf的指针;
不会影响原有ByteBuf的引用数;
retainedSlice()表示在原有slice()方法的基础上,增加原有ByteBuf的引用数;
retainedDuplicate()表示在原有duplicate()方法的基础上,增加原有ByteBuf的引用数;

值的注意的是,get/set操作并不会改变读写指针,而read/write操作则会改变读写指针。

Netty使用了堆外内存,堆外内存不归JVM管理,也就是意味着申请的内存无法被GC回收,需要手动进行内存回收的操作。

其中,Netty中的ByteBuf是通过引用计数进行管理的,如果某个ByteBuf的引用计数降为0时,该ByteBuf将直接回收。

常见易错点

有如下常见易错的地方:

  1. 多次释放
  2. 不释放造成内存泄漏

为避免上述情况发生,只要在增加计数引用地方(包括ByteBuf的创建和手动调用retain()方法),就必须调用release()方法。

示例代码

示例代码ByteBufTest.java

/**
 * @program: learnnetty
 * @description: ByteBuf测试
 * @create: 2020-05-05 16:39
 **/
public class ByteBufTest {
    public static void main(String[] args) {
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(9, 100);
        printDetails("allocate ByteBuf(9, 100)", buffer);

        buffer.writeBytes(new byte[]{1,2,3,4});
        printDetails("writeBytes{1,2,3,4}", buffer);

        buffer.writeInt(12);
        printDetails("writeInt(12)", buffer);

        buffer.writeBytes(new byte[]{12});
        printDetails("writeBytes(12)", buffer);

        buffer.writeBytes(new byte[]{24});
        printDetails("writeBytes(24)", buffer);

        System.out.println("getByte(3):" + buffer.getByte(3));
        System.out.println("getShort(3):" + buffer.getShort(3));
        System.out.println("getInt(3):" + buffer.getInt(3));
        printDetails("getXXX()", buffer);

        buffer.setByte(buffer.readableBytes() + 1, 0);
        printDetails("setXXX()", buffer);

        byte[] dst = new byte[buffer.readableBytes()];
        buffer.readBytes(dst);
        printDetails("readBytes(" + dst.length + ")", buffer);
    }

    private static void printDetails(String title, ByteBuf buffer){
        System.out.println("*************" + title + "*************");
        System.out.println("capacity:" + buffer.capacity());
        System.out.println("maxCapacity:" + buffer.maxCapacity());
        System.out.println("readerIndex:" + buffer.readerIndex());
        System.out.println("readableBytes:" + buffer.readableBytes());
        System.out.println("isReadable:" + buffer.isReadable());
        System.out.println("writerIndex:" + buffer.writerIndex());
        System.out.println("writableBytes:" + buffer.writableBytes());
        System.out.println("isWritable:" + buffer.isWritable());
        System.out.println("maxWritableBytes:" + buffer.maxWritableBytes());
        System.out.println("**************************");
    }
}

输出:

*************allocate ByteBuf(9, 100)*************
capacity:9
maxCapacity:100
readerIndex:0
readableBytes:0
isReadable:false
writerIndex:0
writableBytes:9
isWritable:true
maxWritableBytes:100
**************************
*************writeBytes{1,2,3,4}*************
capacity:9
maxCapacity:100
readerIndex:0
readableBytes:4
isReadable:true
writerIndex:4
writableBytes:5
isWritable:true
maxWritableBytes:96
**************************
*************writeInt(12)*************
capacity:9
maxCapacity:100
readerIndex:0
readableBytes:8
isReadable:true
writerIndex:8
writableBytes:1
isWritable:true
maxWritableBytes:92
**************************
*************writeBytes(12)*************
capacity:9
maxCapacity:100
readerIndex:0
readableBytes:9
isReadable:true
writerIndex:9
writableBytes:0
isWritable:false
maxWritableBytes:91
**************************
*************writeBytes(24)*************
capacity:16
maxCapacity:100
readerIndex:0
readableBytes:10
isReadable:true
writerIndex:10
writableBytes:6
isWritable:true
maxWritableBytes:90
**************************
getByte(3):4
getShort(3):1024
getInt(3):67108864
*************getXXX()*************
capacity:16
maxCapacity:100
readerIndex:0
readableBytes:10
isReadable:true
writerIndex:10
writableBytes:6
isWritable:true
maxWritableBytes:90
**************************
*************setXXX()*************
capacity:16
maxCapacity:100
readerIndex:0
readableBytes:10
isReadable:true
writerIndex:10
writableBytes:6
isWritable:true
maxWritableBytes:90
**************************
*************readBytes(10)*************
capacity:16
maxCapacity:100
readerIndex:10
readableBytes:0
isReadable:false
writerIndex:10
writableBytes:6
isWritable:true
maxWritableBytes:90
**************************
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值