ByteBuf 内部结构设计

一、首先介绍下 ReferenceCounted 接口

public interface ReferenceCounted {
    /**
     * 返回对象的引用数量,如果返回0,表示这个对象已经被释放
     */
    int refCnt();

    /**
     * 引用计数加 1
     */
    ReferenceCounted retain();

    /**
     * 引用计数加 increment
     */
    ReferenceCounted retain(int increment);

    /**
     * 引用计数减 1,如果引用计数为0,则会释放这个对象
     *
     * @return 当且仅当引用计数变为0,并且这个对象已经被释放时返回true
     */
    boolean release();

    /**
     * 引用计数减 decrement,如果引用计数为0,则会释放这个对象
     * @return 当且仅当引用计数变为0,并且这个对象已经被释放时返回true
     */
    boolean release(int decrement);
}

二、ByteBuf介绍

1、ByteBuf实现了ReferenceCounted接口,ByteBuf提供随机和顺序两种方式读取一个或者多个字节序列。

(1)Random Access Indexing

ByteBuf提供类似于原始数组的方式,起始索引是0,结束索引是capacity-1。

(2)Sequential Access Indexing 

ByteBuf 提供两个指针来支持顺序读和顺序写操作。用readIndex来支持读操作,writeIndex来支持写操作。下图展示readIndex 和 writeIndex对ByteBuf进行分段

discardable bytes

这部分表示已经读过的区域,初始为0,最大值为writeIndex,执行读操作时这部分内容会相应的增加。可以通过调用 discardReadBytes 方法来回收这部分区域,达到获取更多writeable byte空间的效果

执行discardReadBytes之前如下图

执行discardReadBytes之后如下图

readable bytes

内容实际存储区域。执行以start或者skip开始的方法时,如果没有足够的内容供读取,会抛出 IndexOutOfBoundsException 异常

writeable bytes

可写区间

(3)Clearing the buffer index

可以调用clear方法来把readIndex 和 writeIndex的值重置为0,但是clear方法不会清空内容。

ByteBuf顺序读和顺序写、随机读和随机写的API都比较简单,此处不介绍。介绍下 ByteBuf 与 java nio 原生 ByteBuffer 转换


/**
     * Returns the maximum number of NIO {@link ByteBuffer}s that consist this buffer.  Note that {@link #nioBuffers()}
     * or {@link #nioBuffers(int, int)} might return a less number of {@link ByteBuffer}s.
     *
     * @return {@code -1} if this buffer has no underlying {@link ByteBuffer}.
     *         the number of the underlying {@link ByteBuffer}s if this buffer has at least one underlying
     *         {@link ByteBuffer}.  Note that this method does not return {@code 0} to avoid confusion.
     *
     * @see #nioBuffer()
     * @see #nioBuffer(int, int)
     * @see #nioBuffers()
     * @see #nioBuffers(int, int)
     */
    public abstract int nioBufferCount();
 
    /**
     * Exposes this buffer's readable bytes as an NIO {@link ByteBuffer}.  The returned buffer
     * shares the content with this buffer, while changing the position and limit of the returned
     * NIO buffer does not affect the indexes and marks of this buffer.  This method is identical
     * to {@code buf.nioBuffer(buf.readerIndex(), buf.readableBytes())}.  This method does not
     * modify {@code readerIndex} or {@code writerIndex} of this buffer.  Please note that the
     * returned NIO buffer will not see the changes of this buffer if this buffer is a dynamic
     * buffer and it adjusted its capacity.
     *
     * @throws UnsupportedOperationException
     *         if this buffer cannot create a {@link ByteBuffer} that shares the content with itself
     *
     * @see #nioBufferCount()
     * @see #nioBuffers()
     * @see #nioBuffers(int, int)
     */
    public abstract ByteBuffer nioBuffer();
 
    /**
     * Exposes this buffer's sub-region as an NIO {@link ByteBuffer}.  The returned buffer
     * shares the content with this buffer, while changing the position and limit of the returned
     * NIO buffer does not affect the indexes and marks of this buffer.  This method does not
     * modify {@code readerIndex} or {@code writerIndex} of this buffer.  Please note that the
     * returned NIO buffer will not see the changes of this buffer if this buffer is a dynamic
     * buffer and it adjusted its capacity.
     *
     * @throws UnsupportedOperationException
     *         if this buffer cannot create a {@link ByteBuffer} that shares the content with itself
     *
     * @see #nioBufferCount()
     * @see #nioBuffers()
     * @see #nioBuffers(int, int)
     */
    public abstract ByteBuffer nioBuffer(int index, int length);
 
    /**
     * Internal use only: Exposes the internal NIO buffer.
     */
    public abstract ByteBuffer internalNioBuffer(int index, int length);
 
    /**
     * Exposes this buffer's readable bytes as an NIO {@link ByteBuffer}'s.  The returned buffer
     * shares the content with this buffer, while changing the position and limit of the returned
     * NIO buffer does not affect the indexes and marks of this buffer. This method does not
     * modify {@code readerIndex} or {@code writerIndex} of this buffer.  Please note that the
     * returned NIO buffer will not see the changes of this buffer if this buffer is a dynamic
     * buffer and it adjusted its capacity.
     *
     *
     * @throws UnsupportedOperationException
     *         if this buffer cannot create a {@link ByteBuffer} that shares the content with itself
     *
     * @see #nioBufferCount()
     * @see #nioBuffer()
     * @see #nioBuffer(int, int)
     */
    public abstract ByteBuffer[] nioBuffers();
 
    /**
     * Exposes this buffer's bytes as an NIO {@link ByteBuffer}'s for the specified index and length
     * The returned buffer shares the content with this buffer, while changing the position and limit
     * of the returned NIO buffer does not affect the indexes and marks of this buffer. This method does
     * not modify {@code readerIndex} or {@code writerIndex} of this buffer.  Please note that the
     * returned NIO buffer will not see the changes of this buffer if this buffer is a dynamic
     * buffer and it adjusted its capacity.
     *
     * @throws UnsupportedOperationException
     *         if this buffer cannot create a {@link ByteBuffer} that shares the content with itself
     *
     * @see #nioBufferCount()
     * @see #nioBuffer()
     * @see #nioBuffer(int, int)
     */
    public abstract ByteBuffer[] nioBuffers(int index, int length);

ByteBuf中不存在 java.nio.ByteBuffer的 allocateDirect(int capacity) 等方法。原因是Netty 对 ByteBuf 的创建单独抽象成一个体系 ByteBufAllocator,包括了直接内存、堆内存,池化的 ByteBuf,后续不断学习,不断补充。

### NettyByteBuf 的用法及常见问题解析 #### 1. ByteBuf 的基本概念 ByteBufNetty 提供的一种高效缓冲区管理工具,用于替代 JDK 自带的 ByteBuffer。它具有更灵活的功能设计和更高的性能表现[^1]。 #### 2. 创建 ByteBuf 实例 以下是创建 ByteBuf 的简单示例代码: ```java public class NettyByteBufExample { public static void main(String[] args) { // 默认分配器创建 ByteBuf 对象 ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); System.out.println(buf); } } ``` 上述代码展示了如何通过 `ByteBufAllocator` 来获取默认的 ByteBuf 实例[^2]。 #### 3. ByteBuf 的存储结构 ByteBuf 的内部存储结构分为三个主要部分:读索引 (`readerIndex`)、写索引 (`writerIndex`) 和容量 (`capacity`)。这些字段共同决定了数据的操作范围和边界。 #### 4. 控制池化功能 Netty 支持通过环境变量配置是否启用内存池机制。如果希望禁用内存池,则可以通过设置如下参数实现: ```properties -Dio.netty.allocator.type=unpooled ``` 反之,若要启用内存池,则将值设为 `pooled` 即可。 #### 5. 高度可扩展性 ByteBuf 接口允许开发者根据实际需求对其进行扩展或自定义实现。例如,在某些特殊场景下可能需要增加额外的方法或属性支持,此时可通过继承现有类或者重新实现接口完成定制开发工作[^4]。 #### 6. 内存泄漏检测 为了防止因不当操作而导致资源未释放而引发的潜在风险,Netty 设计了一套完善的内存泄露监控体系。当发现异常情况时会自动记录相关信息以便排查问题所在位置[^3]。 --- ### 示例代码展示 以下是一个简单的 ByteBuf 使用案例: ```java import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; public class SimpleByteBufUsage { public static void main(String[] args) { // 创建一个非池化的 ByteBuf ByteBuf buffer = Unpooled.buffer(10); // 向 Buffer 写入字节数据 String message = "Hello"; byte[] bytes = message.getBytes(); buffer.writeBytes(bytes); // 输出当前状态信息 System.out.println("Reader Index: " + buffer.readerIndex()); System.out.println("Writer Index: " + buffer.writerIndex()); // 移动 Reader Index 并读取第一个字符 char firstChar = (char) buffer.readByte(); System.out.println("First Character: " + firstChar); // 清理资源 buffer.release(); } } ``` 此程序演示了如何向 ByteBuf 写入字符串并从中提取单个字符的过程。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值