ByteBuf

数据容器

批注 2020-07-07 105759

零拷贝

Netty 零拷贝完全是基于(Java 层面)用户态的,它的更多的是偏向于数据操作优化这样的概念

  1. 通过 wrap 操作把字节数组、ByteBuf、ByteBuffer 包装成一个 ByteBuf 对象, 进而避免了拷贝操作
  2. 支持 slice 操作, 因此可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf,避免了内存的拷贝
  3. CompositeByteBuf 类,它可以将多个 ByteBuf 合并为一个逻辑上的 ByteBuf,避免了各个 ByteBuf 之间的拷贝

使用模式

ByteBuf将数据存储在JVM的堆空间中

ByteBuf heapBuf = ...;
if (heapBuf.hasArray()) {  ← --  检查ByteBuf 是否有一个支撑数组
  byte[] array = heapBuf.array();  ← --  如果有,则获取对该数组的引用 
  int offset = heapBuf.arrayOffset() + heapBuf.readerIndex();  ← --  计算第一个字节的偏移量。
  int length = heapBuf.readableBytes();  ← --  获得可读字节数
  handleArray(array, offset, length);  ← --  使用数组、偏移量和长度作为参数调用你的方法
}

这种模式下的ByteBuf支持通过本地调用分配内存

所以直接缓冲区的数据在堆外,不会被GC处理

ByteBuf directBuf = ...; 
if (!directBuf.hasArray()) {  ← --  检查ByteBuf 是否由数组支撑。如果不是,则这是一个直接缓冲区
  int length = directBuf.readableBytes();  ← --  获取可读字节数
  byte[] array = new byte[length];  ← --  分配一个新的数组来保存具有该长度的字节数据  
  directBuf.getBytes(directBuf.readerIndex(), array);  ← --  将字节复制到该数组
  handleArray(array, 0, length);  ← --  使用数组、偏移量和长度作为参数调用你的方法
}

这种模式下允许多个ByteBuf聚合起来,提供一个ByteBuf整体视图来进行操作

字节级操作

ByteBuf buffer = ...;
for (int i = 0; i < buffer.capacity(); i++) {
  byte b = buffer.getByte(i);
  System.out.println((char)b);
}

不会改变索引的值

批注 2020-07-07 110658

调用discardReadBytes()可以回收可丢弃字节的空间

读取所有数据

ByteBuf buffer = ...;
while (buffer.isReadable()) {
  System.out.println(buffer.readByte());
}

写入数据

ByteBuf buffer = ...;
while (buffer.writableBytes() >= 4) {
  buffer.writeInt(random.nextInt());
}
// 查找回车符(\r)
ByteBuf buffer = ...;
int index = buffer.forEachByte(ByteBufProcessor.FIND_CR);

这些方法都会返回一个新的ByteBuf实例

名称 描述
isReadable() 如果至少有一个字节可供读取,则返回true
isWritable() 如果至少有一个字节可被写入,则返回true
readableBytes() 返回可被读取的字节数
writableBytes() 返回可被写入的字节数
capacity() 返回ByteBuf可容纳的字节数。在此之后,它会尝试再次扩展直 到达到maxCapacity()
maxCapacity() 返回ByteBuf可以容纳的最大字节数
hasArray() 如果ByteBuf由一个字节数组支撑,则返回true
array() 如果 ByteBuf由一个字节数组支撑则返回该数组;否则,它将抛出一个UnsupportedOperationException异常

ByteBufHolder

名称 描述
content() 返回由这个ByteBufHolder所持有的ByteBuf
copy() 返回这个ByteBufHolder的一个深拷贝,包括一个其所包含的ByteBuf的非共享副本
duplicate() 返回这个ByteBufHolder的一个浅拷贝,包括一个其所包含的ByteBuf的共享副本

ByteBuf分配

ByteBufAllocator

实现:

Unpooled缓冲区

提供了一些静态方法来创建ByteBuf实例

ByteBufUtils

引用计数

ByteBuf 与 ByteBufHolder 都实现了引用计数

boolean released = buffer.release();  ← --  减少到该对象的活动引用。当减少到0 时,该对象被释放,并且该方法返回true

访问一个引用计数被释放的对象 会抛出异常