无情 @ 2015-08-03 17:10:42 阅读(1823)
ByteBuffer ByteBuf NIO Netty


我们在进行数据传输的时候经常用的缓冲区,学习ByteBuf前我们先看下java NIO自带的ByteBuffer。

第一:ByteBuffer源码分析

ByteBuffer内部字段

byte[] buff 即内部用于缓存的数组。

position 当前读取的位置。

mark 为某一读过的位置做标记,便于某些时候回退到该位置。

capacity 初始化时候的容量。

limit 读写的上限,limit<=capacity。

put 写模式下,往buffer里写一个字节,并把postion移动一位。写模式下,一般limit与capacity相等。

flip 写完数据,需要开始读的时候,将postion复位到0,并将limit设为当前postion。

get 从buffer里读一个字节,并把postion移动一位。上限是limit,即写入数据的最后位置。 

clear 将position置为0,并不清除buffer内容。 


类图

ByteBuffer存在几大缺点

1:ByteBuffer长度固定,一旦分配完成,它的容量不能所以动态扩展和收缩,常常引发索引越界异常。如:BufferOverflowException

2:ByteBuffer只有一个标识位置的指针position,读写的时候需要手动调用flip()和rewind()等,使用者需要谨慎处理这些API。

3:ByteBuffer的API功能有限,一些高级和使用的特性他不支持,需要开发者手动编程实现。


第二:ByteBuf源码分析

1:ByteBuf实现类

ByteBuf提供了一些较为丰富的实现类,逻辑上主要分为两种:HeapByteBuf和DirectByteBuf,实现机制则分为两种:PooledByteBuf和UnpooledByteBuf,除了这些之外,Netty还实现了一些衍生ByteBuf(DerivedByteBuf),如:ReadOnlyByteBuf、DuplicatedByteBuf以及SlicedByteBuf。

类图结构

HeapByteBuf和DirectByteBuf区别在于Buffer的管理方式:HeapByteBuf由Heap管理,Heap是Java堆的意思,内部实现直接采用byte[] array;DirectByteBuf使用是堆外内存,Direct应是采用Direct I/O之意,内部实现使用java.nio.DirectByteBuffoer。


2、简要的ByteBuf的实现机制


ByteBuf有两个指针,readerIndex和writerIndex,用以控制buffer数组的读写。读逻辑较为简单,不考虑边界的情况下,就是`return array[readerIndex++];`。这里简要分析一下HeapByteBuf的读逻辑。


 1. AbstractByteBuf.ensureWritable(minWritableBytes);


 2. calculateNewCapacity(writerIndex + minWritableBytes)


  > 2.1 判断是否超过可写入容量 maxCapacity – writerIndex


  > 2.2 超过则抛异常,否则计算新容量 writerIndex + minWritableBytes


  > 2.3 判断是否超过设定阈值(4MB),超过每次增加按阈值(4MB)递增,否则


  > 2.4 初始大小为64字节(newCapacity),新容量超过newCapacity则翻倍,直到newCapacity大于新容量为止


  > 2.5 返回Min(newCapacity, maxCapacity);


 3. UnpooledHeapByteBuf.capacity(newCapacity);


  > 3.1 确保可访问,有一个`引用计数`的机制,引用计数为0,则抛异常(ensureAccessible) 


  > 3.2 常规操作:判断是否越界


  > 3.3 如果newCapacity比原容量大,则直接创建新数组,并设置。否则


  > 3.4 如果readerIndex小于新容量,将readable bytes拷贝至新的数组,反之将readerIndex和writerIndex均设置为newCapacity。


 4. setByte(writerIndex++, value)


  > 4.1 确保可访问


  > 4.2 设置