Netty-ByteBuf简析
Netty中ByteBuf的诞生,是因为jdk中的ByteBuffer类操作麻烦,并且存在局限性。
jdk NIO的ByteBuffer存在一下几点问题:
(1) ByteBuffer只维护一个标识位置的指针position,读和写都要手工维护指针位置,操作麻烦。
(2) ByteBuffer长度固定,一旦分配完成,就不能动态扩展,操作大于 ByteBuffer的对象,容易索引越界。
(3) ByteBuffer的API功能有限,一些高级操作需自己实现。
针对以上的问题,ByteBuf的主要设计和工作原理:
(1)底层用的还是ByteBuffer,只是在此基础上做了封装和聚合,既能公用一些基础功能,也能基于此改进和扩展。
(2)ByteBuf维护两个位置指针,一个读,一个写,两个指针互不影响,读指针不会大于写指针。
(3)ByteBuf的动态扩容,原理就是封装一个write方法,里面每次写入时,校验是否到达最大容量,如果是则将数据copy一个新的缓冲区。(采用倍增和步进相结合的算法)
ByteBuf的一些主要功能:
(1)基本的boolean,int,long等数据类型的读和写操作。
(2)discard bytes操作,可以将ByteBuf重用,避免扩容导致性能耗时。
(3)clear操作。将读指针和写指针置0,而不是清空数据。
(4)mark和reset操作。
(5)查找操作。如查找这个ByteBuf对象中的‘/r/n’字符。
(6)derived bytes。
(7)转换成标准的ByteBuffer。
(8)随机读写操作。set和get,可以指定位置写和指定位置读,但是set不支持动态扩容。
· ByteBuf源码分析:
(1) ByteBuf的子类继承体系:
(2)ByteBuf有两个维度的分类:
按内存分:堆内存和直接内存。
按是否使用内存池分:池化和非池化。
举例:PooledHeapByteBuf,就是使用池化并且是使用堆内存的ByteBuf实例。
(3)ByteBuf的内存池实现原理:
PoolArena是一个内存池的实现类。PoolArena由多个chunk组成,而每个chunk有一个或多个page。
chunk将多个page维护成树的结构:例如一个chunk的总大小为64,每个page的大小为4,每个节点存储的是内存地址,
树采用深度优先遍历,但是节点选择是随机的
结构如下图:
具体详细分析,请参看该博客的分析:https://blog.csdn.net/pentiumchen/article/details/45372625;
ByteBuf的相关辅助类:
ByteBufHolder:ByteBuf的容器,是一个抽象对象,供使用者继承扩展用于不同协议。
ByteBufAllocator:字节缓冲区分配器,可分配池化和非池化缓冲区。
CompositeByteBuf:允许将多个ByteBuf组成一个ByteBuf,例如一个ByteBuf是消息头,一个ByteBuf是消息体,那么可以使用该类将两者组合成一个ByteBuf。
ByteBufUtil:ByteBuf操作的工具类。