1、Netty的ByteBuf的优点(重点)
- 存储字节数组是动态的,其最大值默认为Integer.MAX_VALUE这里的动态性是体现write方法中,write方法在执行时会判断Buffer容器,如果不足则自动扩容
- ByteBuf的读索引,写索引完全是分开的
2、ByteBuf知识点
ByteBuf是一个数据容器,用于存储数据,以字节传输
ByteBuf提供readerIndex与writeIndex两个指针操作,mark与reset标识索引
ByteBuf提供duplicate复制方法,它们与原理的数据的readIndex与writerIndex是不一样的,但它们的内部数据是共享的(潜复制)
-
范围关系 0 <= readerIndex <= writeIndex <= capacity
通过索引访问Byte时不会改变真实的读索引与写索引,我们可以通过 ByteBuf的readerIndex与writerIndex方法分别直接修改读索引与写索引
Unpooled:分配10个未池化的内存:ByteBuf buffer = Unpooled.buffer(10);,用完就垃圾回收掉或是清空掉
-
可废弃的字节 Discardable bytes
-
清除缓存 Clearing the buffer indexes
3、 Netty的ByteBuf所提供的3种缓存类型
- Haap Buffer 堆缓存区
- Direct Buffer 直接缓冲区
- Composite Buffer 复合(混合)缓冲区
- 重点:对于后端业务消息的编码来说,推荐使用Heap ByteBuf,对于I/O通信线程在读写缓冲区时,推荐使用Direct ByteBuf
4、 Haap Buffer 堆缓存区
- ByteBuf将数据存储到JVM的堆空间中,并且将实际的数据存放到byte array中实现
- 优点: 由于数据存储在JVM堆中,因此可以快速的创建和快速的释放,并提供了直接访问内部字节数组的方法
- 缺点:每一个读写数据时,都需要首先将数据复制到直接缓存区,在进行Socket网络的传输
5、 Direct Buffer 直接缓冲区
- 在堆之外直接分配内存空间,直接缓存区并不会占用堆的容量空间,因为它是由操作系统在本地内存进行的数据分配
- 优点:在使用Socket进行数据传递时,性能较好,因为数据直接位于操作系统的本地内存中,使用不需要从JVM将数据复制到直接缓冲区中,性能比较好
- 缺点:因为Direct,Buffer是直接在操作系统内存中的,使用内存空间分配与释放要比对空间更加复杂,而且速度要慢一些。
Netty通过提供内存池来解决这个问题,直接缓冲区并不支持通过字节数组的方式来访问数据
6、JDK的ByteBuffer与Netty的ByteBuf的差异对比(重点)
- Netty的ByteBuf采用了读写使用分离的策略,一个初始化(里面尚未有任何数据)的ByteBuf的readIndex与writerIndex值都为0
- 当读索引与写索引处于同一个位置时,如果我们继续读取,那么会抛出IndexOutofBoundsException
- 对于ByteBuf的任何读写操作都会分别单独维护读索引与写索引,maxCapacity最大容量默认的限制就是Integer.MAX_VALUE
7、 JDK的ByteBuffer的缺点
- final byte [] hb; 这是jdk的ByteBuffer对象中用于存储数据的对象声明,可以看到,器字节数组是被声明为了final,也就是长度是固定不变,一旦分配后就不能动态扩容与收缩,而且当待存储的数据字节很大时就很可能出现IndexOutofBoundsException,如果要防御这个异常那就要存储之前完全确定好的待存储的字节大小,如果ByteBuffer的空间不足,只有一个解决方案,创建一个全新的ByteBuffer对象,然后将之前的ByteBuffer中数据复制过去,这一切由开发者手动完成
- ByteBuffer只有使用一个position指针标识位置信息,在进行读写切换时就需要调用flip方法或rewind方法,使用非常不方便