Netty — ByteBuf

小龙 729 2021-08-23

ByteBuf

ByteBuf是Netty提供的,与JDK的ByteBuffer相比,ButeBuf具有更加卓越的功能,使用也更加灵活。

1、ByteBuf的API

ByteBuf提供读访问索引(readerIndex)和写访问索引(WriterIndex)来控制字节数组。ByteBuf的API具有以下的特点

  1. 允许用户自定义缓冲区类型扩展
  2. 通过内置的复合缓冲区类型实现透明的零拷贝
  3. 容量可按需增长
  4. 读写这两种模式之间不需要再调用JDKByteBuffer的filp()方法进行切换
  5. 读和写使用不同的索引
  6. 支持方法链式调用
  7. 执行引用计数
  8. 支持池化

2、ByteBuf类 —— Netty的数据容器

2.1 ByteBuf参数

image.png

  • capacity:指定ByteBuf初始化容量大小
  • maxCapacity: ByteBuf最大容量(允许扩容的最大值)
  • readerIndex:读索引
  • writerIndex:写索引

ByteBuf维护readIndex和writerIndex索引;
当readIndex > writerIndex时,就会抛出异常“IndexOutOfBoundsExcpetion”;
Byteuf容量 = writerIndex;
ByeBuf刻度容量 = writerIndex - readIndex;
readXXX()和writerXXX()方法将会自动推进其对应的索引;
getXXX()和setXXX()方法对readXXX()和writerXXX()无影响

2.2 ByteBuf的使用模式

ByteBuf本质是有一个由不同的索引分别控制读取和写入的字节数组。

ByteBuf有三种模式:

  1. 堆缓冲区模式(Heap Buffer)
  2. 直接缓冲区模式(Direct Buffer)
  3. 复合缓冲区模式(Composite Buffer)

2.2.1 堆缓冲区模式(Heap Buffer)

堆缓冲区模式:又被称为 支撑数组(backing array)。将数据存放在JVM的堆内存中,通过将数据存储在数组中实现

  • 优点:数据存在在JVM堆内存中,可以快速创建和释放,并且支持数组的快速访问。
  • 缺点:每次数据进行I/O传输时,都需要将数据拷贝到缓冲区中
       String str = "hello ByteBuf";
       ByteBuf headBuffer = Unpooled.buffer(16);
       headBuffer.writeBytes(str.getBytes());

2.2.2 直接缓冲区模式(Direct Buffer)

Direct Buffer属于堆外内存,不会占用堆内存。适用于套接字传输过程,避免了数据从内不缓冲区拷贝到直接缓冲区的过程,性能更好

  • 优点:使用Socket传输数据时性能更好,避免了数据从JVM堆内存拷贝到直接缓冲区的过程,提升了性能
  • 缺点:相对于堆缓冲区而言,Direct Buffer分配内存空间和释放内存的开销更大
  • 使用场景:对于涉及大量I/O数据读写,建议使用Direct Buffer。而用于对消息进行编解码,建议使用Heap Buffer
        ByteBuf directBuffer = Unpooled.directBuffer(16);
        String str = "hello direct buffer";
        directBuffer.writeBytes(str.getBytes());
        int length = directBuffer.readableBytes();
        byte[] bytes = new byte[length];
        directBuffer.getBytes(directBuffer.readerIndex(), bytes);
        System.out.println(length);
        System.out.println(bytes.length);
        System.out.println(new String(bytes));

2.2.3 复合缓冲区模式(Composite Buffer)

Composite Buffer是Netty特有的缓冲区。类似于提供一个或多个ByteBuf的组合视图,可以根据需要添加和删除不同类型的ByteBuf

  • Composite Buffer:是一种组合视图,提供一种方式让使用者自有组合多个ByteBuf,避免了拷贝和分配新缓冲区
  • Composite Buffer:不支持访问其支持数组,如果要访问,需要先将内容拷贝到堆内存中,在进行访问
  • COmposite Buffer由头部和主体组成,头部和主体组合在一起没有进行任何复制过程,仅仅是创建了一个视图

image.png

        CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
        ByteBuf headBuffer = Unpooled.buffer(); // 也可以使用直接内存
        headBuffer.writeBytes("你好".getBytes());
        ByteBuf bodyBuffer = Unpooled.directBuffer(); // 也可以使用堆内存
        bodyBuffer.writeBytes("堆内存缓冲区".getBytes());
        compositeByteBuf.addComponents(headBuffer,bodyBuffer);
        for (ByteBuf buf : compositeByteBuf){
            if (buf.hasArray()){ // 是堆内存缓冲区
                System.out.println(new String(buf.array()));
            }else { // 是直接内存缓冲区
                int length = bodyBuffer.readableBytes(); // 缓冲区长度
                byte[] bytes = new byte[length];
                buf.getBytes(buf.readerIndex(), bytes);
                System.out.println(new String(bytes));
            }
        }

2.3 字节级操作

2.3.1 随机访问索引


# Netty # ByteBuf