Netty源码分析(五)—ByteBuf源码分析
在进行数据传输时往往需要使用缓冲区,Java NIO中使用Buffer作为缓冲区;七种基本数据类型都有自己的缓冲区实现,最常使用的是ByteBuffer,但是ByteBuffer也有局限性;
Netty实现了缓冲区的池化技术,在一定程度上减少了频繁内存分配和GC带来的性能损耗
个人主页:tuzhenyu’s page
原文地址:Netty源码分析(五)—ByteBuf源码分析
(0) ByteBuffer和ByteBuffer
ByteBuffer的缺点
ByteBuffer长度固定,通过ByteBuffer.allocate()方法或者ByteBuffer.wrap()方法分配后容量不能动态的扩展和收缩;
ByteBuffer只有一个标识位置的指针position,读写数据时候需要调用flip()方法或者rewind()方法调整指针位置;
ByteBuffer的API功能有限,一些高级和实用的性能不支持
ByteBuf的优点
每次写入数据会判断容量是否足够,如果不够则重新创建缓冲区并进行数据复制,实现缓冲区的容量大小可以随着需求动态改变
使用读指针和写指针代替position指针,实现在读写模式之间切换不需要调用ByteBuffer的flip()方法
从内存分配来看,ByteBuf分为堆内存和直接内存两类UnpooledHeapByteBuf和UnpooledDirectByteBuf,上层使用相同的封装;
从内存使用上分为基于对象池的ByteBuf和普通的ByteBuf,基于对象池的ByteBu会重用池中的ByteBuf对象,提高内存的实用率,避免由高负载导致的频繁的触发GC;
(1) ByteBuffer的继承结构
ByteBuf是Netty缓存区的顶层抽象类,定义了缓存区操作的所有API;
ByteBuf的直接间接实现类有AbstractByteBuf和AbstractReferenceCountedByteBuf,在这两个类中实现了一些公共功能的函数,AbstractReferenceCountedByteBuf按照内存实用情况分为基于内存池的PooledByteBuf和普通的UnPooledHeapByteBufer等;
普通的不基于内存池的缓冲区按照内存分配情况分为UnPooledHeapByteBuf堆缓存区,UnPooledDirectByteBuf直接缓存区和UnPooledUnsafeDirectByteBuf等
基于内存池的缓冲区PooledByteBuf根据内存分配的情况分为PooledDirectByteBuf,PooledHeapByteBuf和PooledUnsafeDirectByteBuf等;
(2) ByteBuf的功能
- 顺序读操作(ByteBuf.readXxx()),类似于ByteBuffer的get()方法
int readInt(); //从readerIndex开始读取4个字节转换成整型数值返回,将readerIndex值增加4
long readLong(); //从readerIndex开始读取8个字节转换成长整型数值返回,将readerIndex值增加8
ByteBuf readBytes(byte[] bytes) //从readerIndex开始读取bytes.length长度的字节数,并封装成ByteBuf类型返回
- 顺序写操作(ByteBuf.writeXxx()),类似于ByteBuffer的put()方法
ByteBuf writeInt(int value) //将参数写入到当前ByteBuf中,操作成功后writeIndex+=4
ByteBuf writeLong(long value) //将参数写入到当前ByteBuf,操作成功后writeIndex+=8
ByteBuf writeBytes(byte[] bytes) //将字节数组写入到当前的ByteBuf中,操作成功后writeIndex+=bytes.length
- 随机读操作(ByteBuf.getXxx())
int getInt(int index) //从index索引处读取4个字节转换成整型数值返回
long getLong(int index) //从index索引处读取8个字节转换成整型数值返回
ByteBuf getBytes(int index,byte[] bytes) //从index索引处读取bytes.length个字节封装成ByteBuf返回;
- 随机写操作(ByteBuf.setXxx())
ByteBuf setInt(int index,int value) //将value写入到从readerIndex开始的4个字节中
ByteBuf setLong(int index,long value) //将value写入到从readerIndex开始的8个字节中;
ByteBuf setBytes(int index,byte[] bytes) //将bytes字节数组写入到从readerIndex开始的bytes.length长度的字节中;
- 复制操作(duplicate和copy)
Bytebuf byteBuf.duplicate() //返回一个复制的ByteBuf对象,该对象和被复制的ByteBuf共享一块缓冲区内存,只是维护着自己独立的读写索引,修改一个另外一个也会变化;
ByteBuf byteBuf.copy() //复制一个新的ByteBuf对象,内容和索引都是独立的不会相互影响;
- 查找操作(indexOf和bytesBefore)
int indexOf(int fromIndex,int toIndex,byte value) //从当前ByteBuf对象中查找value首次出现的位置,查找起始索引是fromIndex,终点索引是toIndex,如果没查找到则返回-1;
int bytesBefore(byte value) //从当前ByteBuf对象中查找value首次出现的位置,查找起始索引是readerIndex,终点索引是writerIndex,如果没查找到则返回-1;