11、Netty的ByteBuf缓冲区

优化点

netty重写了Java的ByteBuff,具体有哪些优点

  • pooling池化,减少了内存的复制和GC。提升了效率
  • 复合缓冲区,支持0复制
  • 不需要调用flip()的方法切换读写。
  • 可以自定义缓冲区类型(Heap Buff 和direct buff)。
  • 可以进行引用计数。来标记是否可GC

ByteBuf的逻辑部分

分为4个部分

  • 已用字节:表示已经使用完的无用的字节
  • 可读字节:这部分是ByteBuf保存的有效数据,从ByteBuf中读取的数据都是这部分数据
  • 可写字节:写入到ByteBuf中的数据都是这一部分数据。
  • 可扩容字节:表示该ByteBuf最多还能扩容多少字节

在这里插入图片描述

ByteBuf的重要属性

  • readerIndex(读指针):指示读的起始位置。每读取1个字节,readerIndex 自动+1,当readerIndex==writeIndex时,表示不可读
  • writeIndex(写指针):指示写的起始位置。每写1个字节,writeIndex自动+1,当 writeIndex==capacity()
    表示不可写,但是netty会自动扩容,capacity()是一个成员方法,不是最大容量。
  • maxCapacity(最大容量):当前ByteBuf最大可容纳的字节数量。当超过最大容量时,抛异常

ByteBuf的三组方法

  • 容量系列
    capacity():表示ByteBuf的容量,它是 废弃的字节数+可读的字节数+可写的字节数 之和

    maxCapacity():表示ByteBuf的最大容量,当向ByteBuf中写入数据的时候,如果发现当前容量不足,
    则自动扩容,直到扩容到maxCapacity设定的上限

  • 写入系列
    isWritable():是否可写
    writableBytes():可写入的字节数
    writableBytes(byte[] bytes):把bytes中的字节全部写入到 ByteBuf中
    writeType(TYPE value):写入基本数据类型

  • 读取系列:
    isReadable():是否可读
    readableBytes():当前可读的字节数
    readBytes(byte[] bytes):读取bytes中的字节
    readType():读取的数据类型,可以读取8大基本类型

在这里插入图片描述

ByteBuf的引用计数

ByteBuf引入计数器来对ByteBuf进行GC回收

当创建完一个ByteBuf的时候,它的引用就为1,每次调用retain()方法时,它的引用就+1,每次调用release()时,它的引用就-1

当引用为0的时候,表示这个ByteBuf可被GC回收。

为了确保引用计数不会混乱,在netty的业务处理器开发过程中,应该坚持1个原则:
retain和release方法应该结对使用,在一个方法中调用一次retain(),就应该调用一次release();

netty4.0的版本默认是非池化,但是也可设置池化。4.1的版本默认是池化
当引用计数器为0,netty会进行ByteBuf的回收,分2种情况:

  • Pooled池化,回收方法是:放入可重新分配的ByteBuf池中,等待下次分配
  • Unpooled 非池化的ByteBuf缓冲区,回收分2中
    1)如果是堆(Heap)结构缓冲,会被JVM的垃圾回收机制回收。
    2)如果是直接内存(Direct)类型,调用本地方法释放外部内存(unsafe.freeMemory)

ByteBuf的分配(Allocator分配器)

netty提供了ByteBufAllocator分配器的两种实现:

  • PoolByteBufAllocator 池化分配器(netty4.1 版本默认)
  • UnpooledByteBufAllocator 非池化分配器(netty4.0及以前的版本默认创建)

缓冲区类型:

在这里插入图片描述

这三种缓冲区在分配的时候,都可以分配成池化和非池化的。

直接缓冲区(Direct ByteBuf):

  • 不属于java堆内存,所分配的内存是调用操作系统malloc()函数获得的。由netty的本地内存堆native堆进行管理
  • 容量可指定,如果不指定,默认与Java堆大小相等
  • Direct Memory避免了Java堆与native堆的来回复制,在某些应用场景下,提高了性能
  • Direct Buf的读写比Heap Buf快,但是创建和销毁比较慢,所以直接缓冲区适合在池化的情况下使用
  • 在需要频繁的创建和销毁缓冲区的场合,由于创建和销毁直接缓冲区(Direct Buffer)的代价比较高昂,所以不建议使用
  • 创建直接缓冲区:ByteBufAllocator.DEFAULT.directBuffer();

ByteBuf的释放

分2种情况

  • 自动释放:通道流水线channelPipeline的最后一个节点是TailHandler,在这个节点自动释放
  • 手动释放: 通道流水线截断时,需要调用byteBuf.release(),来手动释放
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值