本章主要介绍ByteBuffer的功能和源码分析
一、Java NIO自带了byteBuffer
Java NIO自大的ByteBuffer有缺点:
- 长度固定,一旦分配完成后,不能动态进行扩容和收缩
- 只有一个标识位置的指针position,读的时候需要自行调用flip()和rewind()等,很容易出错
- API功能有限,一些高级的特性不支持。
基于此,Netty的ByteBuffer参考了Java ByteBuffer的设计,解决已有的问题,并重新封装了一些API。
二、Netty的ByteBuffer
1、Netty的ByteBuffer提供两个指针变量用于顺序读和顺序写,ReadIndex和WriteIndex。两个指针将Buffer分成3个区域,读取的数据只能位于readIndex和writeIndex之间,可写数据位于writeIndex和capacity之间。0到readIndex之间的区域是已经读取过的区域,可以调用discardReadBytes来重用这部分区间,以节约内存,防止Buffer的动态扩张。
2、clear操作,并不会清空buffer的存储内容,而是用来充值readIndex和writeIndex,position,Mark和limit的,将他们还原为初始设置值。
3、Mark和reset,Mark操作会将当前的位置指针备份到Mark变量中,调用reset后会将指针恢复到备份的位置,这种操作主要是因为对于某些读写需要回滚。
三、Buffer源码分析
从存储结构上,buffer分为堆内存和直接内存buffer。堆内存的特点是分配和回收速度快,也能被JVM自动管理,缺点是做Socket IO 操作时,需要从用户态拷贝到内核态,多一次复制操作。
直接内存buffer在堆外分配,缺点是分配和回收速度慢,但是做Socket IO操作时,会少一次内存拷贝。
结合他们的特点,经验表明,在IO通信是使用directBuffer,在后端业务编码时采用HeapByteBuffer。
Netty的容量自动扩展,在小于4M的时候,采用倍增;大于等于4M时,采用每次增加4M。