优化点
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)