在数据传递的时候往往需要使用缓冲区,常用的缓冲区是Java NIO 提供的Buffer,ByteBuf是Java NIO ByteBuffer的替代。
Buffer类详解
缓冲区Buffer就是内存中预留指定大小的空间用于IO数据的临时存储。有了缓冲区后,会减少实际的物理读写次数,而且这块区域一直被重复利用,降低了动态分配和内存回收次数。底层是线性数组,所以容量是固定的,通过mark,position和limit控制数组的写入和读取。
属性
Capacity | 初始化时候的容量 |
Limit | 对于写入模式,表示当前可以写入的数组大小,默认为数组的最大长度,对于读取模式,表示当前最多可以读取的数据的位置下标; |
Position | 当前读取的位置 |
Mark | 为读过的位置坐标记,便于回退 |
属性间的关系:mark <= position <= limit <= capacity
方法
put | 写模式,往buffer写数据,并把position移动一位 |
flip | 写完数据后,开始读的时候,将position复位到0,并将limit设为当前的position |
get | 读数据,position后移 |
clear | 不清楚数据,position置为0 |
mark | 标记到一个特定的position |
reset | 回到标记 |
allocate | 创建一个指定的buffer |
compact | 读取模式下进行数据压缩,并且方便下一步继续写入数据,类似空出字节,供下一次写入,position指向下一个可写入的位置 |
ByteBuf详解
ByteBuf依然是一个byte数组,与buffer功能类似。不过是通过两个位置指针来协助缓冲区的读写,读使用readIndex,写使用writeIndex。readIndex和writeIndex一开始取值都是0,数据写入会使writeIndex增加,读取会使readIndex增加,但是readIndex小于writeIndex。读取之后,0到readIndex是discard的,调用discardReadBytes会释放这部分空间。readIndex和writeIndex直接的数据是可读的。writeIndex到capacity直接的空间是可写的。
在写入的时候,会对剩余空间进行检查,空间不足,则创建新的ByteBuf,释放老的ByteBuf。如何扩容的呢?先计算扩展后的容量(writeIndex+minWriteBytes),也就是最小要求的容量,扩容的时候有个门限值4MB,如果新增的容量正好等于门限值,则使用门限值,如果大于门限值,每次采用步进4MB的方式扩容,小于门限值,则以64为计数进行倍增,直到倍增的结果大于或等于需要的容量值。