Netty的ByteBuf是JDK中ByteBuffer的升级版,提供了NIO buffer和byte数组的抽象视图。

ByteBuf的主要类集成关系:

(图片来自Netty权威指南,图中有一个画错的地方是PooledByteBuf中的最后一个子类应该是PooledUnsafeDirectByteBuf)

从继承关系可以看出AbstractReferenceCountedByteBuf的子类分为两类:Pooled和Unpooled的ByteBuf。

Pooled ByteBuf是基于对象池的ByteBuf(会被缓存),Unpooled则是普通的ByteBuf对象。

无论是否基于内存池的ByteBuf,它的子类有分为DirectByteBuf和HeapByteBuf分别表示在堆外内存分配的缓冲区和在堆内存的缓冲区。

堆内存缓冲区的特点是分配和回收速度快,可以被JVM自动回收;缺点是如果进行Socket的IO读写,需要额外做一次内存复制。

堆外内存的缓冲区相对于堆内存的缓冲区,分配和回收的速度会慢一些,但是将它写入或从Socket Channel读取数据是,会少一次内存复制,速度比堆内存更快一些。

BufferBuf也提供了一类API来将自己转化成为ByteBuffer以便于在需要ByteBuffer的地方进行操作。

AbstractByteBuf

AbstractByteBuf定义了ByteBuf的基础属性和一些公用的方法。

主要成员变量有:

readerIndex

writerIndex

markedReaderIndex

markedWriterIndex

maxCapacity

可以看到ByteBuf中分别定义了读写游标,也就是说读游标和写游标是分离的,这相对于ByteBuffer只使用一个position,在读写操作时会便利很多。

一块缓冲区会被两个游标分隔为三块区域,分别是已经读取过的、可读的、剩余可写的。

在写入数据后可以直接开始读取,不需要flip操作。

另外AbstractByteBuf中的方法分为三类:

读取数据、写入数据、操作游标

读取操作分为readXXX和getXXX,以读取Long为例,

readLong()方法在当前readerIndex位置读取8个Byte并增加readerindex的值;

getLong(int index)则需要接收一个index参数,从index位置开始读取8个Byte,get操作不会改变readerIndex的值。

写入操作也有两类,分别是setXXX和writeXXX,

writeLong(long value)方法在当前writerIndex位置开始写入一个Long值并增加writerIndex的值;

setLong(int index, long value)方法则接收一个index参数作为写入的位置,写入操作不修改writerIndex的值。

索引操作就是通过setReaderIndex之类的方法改变readerIndex的值来重新读取数据,非常简单,不做说明。

AbstractReferenceCountedByteBuf

从类名上看,AbstractReferenceCountedByteBuf主要是实现了对引用的计数,类似于JVM内存回收的对象引用计数器,用于跟踪对象的分配和销毁。

只有一个成员变量:refCnt,看命名也知道是用于计数的,并且用AtomicIntegerFieldUpdater来实现线程安全的计数。 

retain API用于增加引用的计数。

release则用于减少计数值。

定义deallocate方法让子类去实现当引用计数为0时的操作(由子类实现具体的“回收”操作)。

UnpooledHeapByteBuffer

UnpooledHeapByteBuffer是不适用对象池,且直接在堆内存上分配的缓冲区。 

ByteBufAllocator alloc:创建了这个缓冲区的分配器

byte[] array:底层存储

ByteBuffer tmpNioBuf:Nio  ByteBuffer对象,用于将自身转换成一个ByteBuffer对象

构造方法非常简单:

记录分配器alloc;

初始化数组;

将读写位置调整为0;

这个构造方法则是传入byte数组做初始化,writerIndex调整到数组后的第一个位置。

两个构造方法都有maxCapacity参数,且初始容量要么是initialCapacity要么是initalArray的长度,说明缓冲区的大小是可以调整的,最大不超过maxCapacity。

通过capacity来调整缓冲区的大小。如果newCapacity小于当前array的length,那么会有部分数据被丢弃。如果newCapacity超过array的length,那么新扩容的位置数据未空。

UnpooledDirectByteBuf

ByteBufAllocator alloc:使用的分配器

ByteBuffer buffer:内部用于存储数据的结构

ByteBuffer tmpNioBuf:临时的ByteBuffer,在将自己转换成ByteBuffer对象时会使用

int capacity:容量

doNotFree:标志ByteBuffer是否可以回收

区别于UnpooledHeapByteBuf,UnpooledDirectByteBuf的扩容操作不在是申请数组进行数据拷贝,而是申请新的ByteBuffer之后进行收拷贝,而ByteBuffer一定是Direct的。

deallocate实现了底层存储ByteBuffer的回收操作,即在引用计数为0时将DirectByteBuffer回收掉(DirectByteBuffer的内存是由自己回收的,而不是JVM)。

UnpooledUnsafeDirectByteBuf

UnpooledUnsafeDirectByteBuf和UnpooledUnsafeDirectByteBuf的区别在于UnpooledUnsafeDirectByteBuf直接使用ByteBuffer来操作数据,而UnpooledUnsafeDirectByteBuf采用Unsafe来操作数据。

UnpooledUnsafeDirectByteBuf的_getLong实现:

UnpooledUnsafeDirectByteBuf的_getLong实现:

AbstractReferenceCountedByteBuf子类的另一个分支是PooledByteBuf,即使用对象池,会被缓存的ByteBuffer。

PooledByteBuf有三个子类:

PooledHeapByteBuf

PooledDirectByteBuf

PooledUnsafeDirectByteBuf

他们分别和Unpooled的几个子类对应。

对于Pooled的实现,详见Netty对象池实现分析。

欢迎关注我的个人公众号,会写一些列关于消息中间件的文章,也欢迎交流任何技术问题,或者扯扯淡。

Netty ByteBuf源码分析的更多相关文章

  1. Netty学习篇⑥--ByteBuf源码分析

    什么是ByteBuf? ByteBuf在Netty中充当着非常重要的角色:它是在数据传输中负责装载字节数据的一个容器;其内部结构和数组类似,初始化默认长度为256,默认最大长度为Integer.MAX ...

  2. netty : NioEventLoopGroup 源码分析

    NioEventLoopGroup 源码分析 1. 在阅读源码时做了一定的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限.为了方便 IDE 查看.跟踪.调试 代码,所以在 github ...

  3. netty UnpooledHeapByteBuf 源码分析

    UnpooledHeapByteBuf 是基于堆内存进行内存分配的字节缓冲区,没有基于对象池技术实现,这意味着每次I/O的读写都会创建一个新的UnpooledHeapByteBuf,频繁进行大块内存的 ...

  4. 【Netty】源码分析目录

    前言 为方便系统的学习Netty,特整理文章目录如下. [Netty]第一个Netty应用 [Netty]Netty核心组件介绍 [Netty]Netty传输 [Netty]Netty之ByteBuf ...

  5. netty(六) buffer 源码分析

    问题 : netty的 ByteBuff 和传统的ByteBuff的区别是什么? HeapByteBuf 和 DirectByteBuf 的区别 ? HeapByteBuf : 使用堆内存,缺点 ,s ...

  6. NIO-EPollSelectorIpml源码分析

    目录 NIO-EPollSelectorIpml源码分析 目录 前言 初始化EPollSelectorProvider 创建EPollSelectorImpl EPollSelectorImpl结构 ...

  7. Netty源码分析第5章(ByteBuf)---->第1节: AbstractByteBuf

    Netty源码分析第五章: ByteBuf 概述: 熟悉Nio的小伙伴应该对jdk底层byteBuffer不会陌生, 也就是字节缓冲区, 主要用于对网络底层io进行读写, 当channel中有数据时, ...

  8. Netty源码分析第5章(ByteBuf)---->第2节: ByteBuf的分类

    Netty源码分析第五章: ByteBuf 第二节: ByteBuf的分类 上一小节简单介绍了AbstractByteBuf这个抽象类, 这一小节对其子类的分类做一个简单的介绍 ByteBuf根据不同 ...

  9. Netty源码分析第5章(ByteBuf)---->第3节: 缓冲区分配器

    Netty源码分析第五章: ByteBuf 第三节: 缓冲区分配器 缓冲区分配器, 顾明思议就是分配缓冲区的工具, 在netty中, 缓冲区分配器的顶级抽象是接口ByteBufAllocator, 里 ...

随机推荐

  1. 细说C#中的系列化与反系列化的基本原理和过程

    虽然我们平时都使用第三方库来进行系列化和反系列化,用起来也很方便,但至少得明白系列化与反系列化的基本原理. 注意:从.NET Framework 2.0 开始,系列化格式化器类SoapFormatte ...

  2. Python列表(一)

    列表由一系列特定顺序排列的元素组成,在python中使用[]来表示列表,并用,来进行元素分割. >>> name_list['alben', 'james', 'harden', ' ...

  3. JS 浏览器cookie的设置,读取,删除

    JavaScript是运行在客户端的脚本,因此一般是不能够设置Session的,因为Session是运行在服务器端的. 而cookie是运行在客户端的,所以可以用JS来设置cookie. 假设有这样一 ...

  4. Local模式下Spark程序只输出关键信息

    使用spark-submit提交local任务时,会输出很多Info信息: ------------------------------------------- Time: ms --------- ...

  5. 手把手教你用Eclipse+TestNG搭建接口自动化测试框架

    转载于:http://qa.blog.163.com/blog/static/190147002201510275306185/ 把群博里关于接口自动化的文章都看了一遍,都是关于测试过程中遇到的问题及 ...

  6. unity3D:游戏分解之角色移动和相机跟随

          游戏中,我们经常会有这样的操作,点击场景中某个位置,角色自动移动到那个位置,同时角色一直是朝向那个位置移动的,而且相机也会一直跟着角色移动.有些游戏,鼠标滑动屏幕,相机就会围绕角色旋转. ...

  7. [github项目]基于百度地图二次开发实现的车辆监管(包含车辆定位、车辆图片和方向控制,电子围栏,图形绘制等功能)前端实现(不包含后端实现)

    前言:基于百度地图javascript版本开发,百度地图中所用的key已承诺仅用于测试,不用于商业用途 注:本文所有代码可以到github上进行下载,github地址:http://map.eguid ...

  8. 安装xampp出错,安装xampp出错,windows找不到-n ?

    安装路径错误的问题 安装参考路径:D:\xampp\子文件

  9. angular表单验证实例----可用的代码

    前段时间,公司做一个单页面,就是一个表单验证,早开始在菜鸟教程上关注了angular,所以下派上用场了 angular里面对于表单验证,设置了很多指令. 也就是说不用自己写一些逻辑,直接绑定指令就行. ...

  10. 用php+mysql+ajax实现淘宝客服或阿里旺旺聊天功能 之 前台页面

    首先来看一下我已经实现的效果图: 消费者页面:(本篇随笔) (1)会显示店主的头像 (2)当前用户发送信息显示在右侧,接受的信息,显示在左侧 店主或客服页面:(下一篇随笔) (1)在左侧有一个列表 , ...