暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Netty中ByteBuf的数据结构

看点有用的 2021-08-22
1028

ByteBuf是Netty中最重要、最基础的数据结构,所有通过网络传输的数据都是用ByteBuf进行读写的。ByteBuf封装了Java NIO中的ByteBuffer类,所以其底层是通过ByteBuffer实现的,但同时解决了其扩展困难、操作复杂和无法扩容的问题。


ByteBuf维护了两个指针和三个区域,两个指针是读索引(readIndex)和写索引(writeIndex),三个区域是可丢弃字节区(discardable bytes)、可读字节区(readable bytes)和可写字节区(writable bytes)。其示意图如下所示。

在上图中,0表示ByteBuf维护内存区域的起始位置,capacity表示ByteBuf维护内存区域的最大容量(可扩展),readIndex和writeIndex在0和capacity之间移动,如果任何一个操作导致readIndex和writeIndex小于0或大于capacity,则会报IndexOutOfBoundsException异常。


有了基本的数据结构,那么当ByteBuf在操作读、写、扩容和回收时,指针和数据区域是如何变化的呢?


读操作


当执行ByteBuf的readXxx()方法的时候,主要操作的是readIndex指针,此时每读一个字节,readIndex指针会向右移动一位,直到等于writeIndex。此时readable bytes区域会逐渐缩小以至消失,discardable bytes区域会逐渐扩大至writeIndex的位置,表示ByteBuf中的数据已读完。其示意图如下。

如果任何一个操作导致readIndex大于writeIndex,则会报IndexOutOfBoundsException异常。


写操作


当执行ByteBuf的writeXxx()方法的时候,主要操作的是writeIndex指针,此时每写一个字节,writeIndex指针会向右移动一位,直到等于capacity,如果仍有待写入内容,则会触发ByteBuf的扩容机制。此时writable bytes区域会缩小以至消失,readable bytes区域会逐渐扩大至capacity的位置,表示ByteBuf的数据写入完毕。其示意图如下。

扩容


ByteBuf的扩容发生在写操作的时候,此时不仅writeIndex会向右移动(在新数据结构中),capacity也会向右移动(在新数据结构中),直到数据全部写完。扩容操作涉及到扩容策略和数据的拷贝,具体策略后面专文分析。其示意图如下。

回收


随着discardable bytes区域的扩大,如果不能及时回收,会造成内存的浪费。ByteBuf的回收需要先对数据进行拷贝,然后再重置索引。数据拷贝用的方法是ByteBuf的setBytes方法,将readable bytes中的数据拷贝至缓存区的起始位置,然后将readIndex设置为0,writeIndex设置为writeIndex-readIndex。其示意图如下。

ByteBuf的实现类


上面介绍了ByteBuf的基本操作原理,要知道ByteBuf是个接口类,具体操作还需要通过具体的实现类来实现。按内存分配和内存回收的方式不同,有四个实现类:UnpooledHeapByteBuf、PooledHeapByteBuf、UnpooledDirectByteBuf、PooledDirectByteBuf。


堆内存
直接内存
对象池
PooledHeapByteBuf
PooledDirectByteBuf
非对象池
UnpooledHeapByteBuf
UnpooledDirectByteBuf


  • PooledHeapByteBuf

    基于对象池的堆内存ByteBuf,内存分配时可重用对象池中的ByteBuf对象,可以提升内存的使用效率,降低由于高负载导致的频繁GC。另外其内存分配在堆上,内存的分配和回收速度快,可以被JVM自动回收;缺点是进行Socket IO时,需要将数据在堆内存和内核之间进行拷贝,IO性能会有一定下降。

  • PooledDirectByteBuf

    同PooledHeapByteBuf一样,通过内存池来管理对象的创建和回收,但内存创建在堆外(即内核上),在进行Socket IO时,无需进行数据的拷贝,IO性能比PooledHeapByteBuf高。

  • UnpooledHeapByteBuf

    非基于对象池的ByteBuf,即创建对象时直接new对象。其创建的对象位于堆上,与PooledHeapByteBuf相比,没有对象池的管理环节,实现起来更简单。

  • UnpooledDirectByteBuf

    非基于对象池的ByteBuf,其创建的对象位于堆外,具有非对象池和直接内存的优点,同时也具有其缺点。


以上常见ByteBuf实现类各有其特点,我们在Netty编程时可以根据业务场景灵活使用。

文章转载自看点有用的,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论