结构
1.以上三段内容是被两个指针给划分出来的,从左到右,依次是读指针(readerIndex)、写指针(writerIndex),<br>然后还有一个变量 capacity,表示 ByteBuf 底层内存的总容量<br>
2.从 ByteBuf 中每读取一个字节,readerIndex 自增1,ByteBuf 里面总共有 writerIndex-readerIndex 个字节可读, <br>由此可以推论出当 readerIndex 与 writerIndex 相等的时候,ByteBuf 不可读<br>
3.写数据是从 writerIndex 指向的部分开始写,每写一个字节,writerIndex 自增1,直到增到 capacity,这个时候,表示 ByteBuf 已经不可写了
4.ByteBuf 里面其实还有一个参数 maxCapacity,当向 ByteBuf 写数据的时候,如果容量不足,那么这个时候可以进行扩容,<br>直到 capacity 扩容到 maxCapacity,超过 maxCapacity 就会报错<br>
三种模式
堆缓冲区模式(Heap Buffer)
支撑数组(backing array)。将数据存放在JVM的堆空间,通过将数据存储在数组中实现
优点
由于数据存储在Jvm堆中可以快速创建和快速释放,并且提供了数组直接快速访问的方法
缺点
每次数据与I/O进行传输时,都需要将数据拷贝到直接缓冲区
直接缓冲区模式(Direct Buffer)
堆外分配的直接内存,不会占用堆的容量。<br>适用于套接字传输过程,避免了数据从内部缓冲区拷贝到直接缓冲区的过程,性能较好<br>
优点
使用Socket传递数据时性能很好,避免了数据从Jvm堆内存拷贝到直接缓冲区的过程。提高了性能
缺点
相对于堆缓冲区而言,Direct Buffer分配内存空间和释放更为昂贵
对于涉及大量I/O的数据读写,建议使用Direct Buffer。<br>而对于用于后端的业务消息编解码模块建议使用Heap Buffer<br>
复合缓冲区模式(Composite Buffer)
本质上类似于提供一个或多个ByteBuf的组合视图,可以根据需要添加和删除不同类型的ByteBuf。
内存管理
Netty 的 ByteBuf 是通过引用计数的方式管理的,如果一个 ByteBuf 没有地方被引用到,需要回收底层内存
默认情况下,当创建完一个 ByteBuf,它的引用为1,然后每次调用 retain() 方法, 它的引用就加一,<br> release() 方法原理是将引用计数减一,减完之后如果发现引用计数为0,则直接回收 ByteBuf 底层的内存。<br>
多个 ByteBuf 可以引用同一段内存,通过引用计数来控制内存的释放,遵循谁 retain() 谁 release() 的原则
slice()、duplicate() 共用同一个内存<br>
copy() 新的内存<br>
retainedSlice() 与 retainedDuplicate() 同一个内存增加引用计数次数<br>