ByteBuf

数据容器

批注 2020-07-07 105759

零拷贝

Netty 零拷贝完全是基于(Java 层面)用户态的,不同于操作系统中的零拷贝,操作系统的零拷贝描述的是用户态与内核态之间的内存拷贝。Netty 的更多的是偏向于数据操作优化:

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

使用模式

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

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