引子
java NIO 使用ByteBuffer作为字节容器,使用上过于复杂,为此netty使用ByteBuf来代替ByteBuffer。
ByteBuf的API
- Netty的数据处理API通过两个组件暴露:ByteBuf和ByteBufHolder。
- ByteBuf维护了两个不同的索引:readerIndex和writerIndex,分别用于读写。
我们在ByteBuf的源码的注释中看到:
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
指针在readerIndex到writerIndex的区间中是可以进行读数据的,在writerIndex到capacity的区间中是可以写数据的。ByteBuf执行read操作时,readIndex指针往后移动;执行write操作时,writeIndex指针往后移动。
ByteBuf使用模式
HEAP BUFFER(堆缓冲区)
最常用的类型是 ByteBuf 将数据存储在 JVM 的堆空间,这是通过将数据存储在数组的实现。堆缓冲区可以快速分配,当不使用时也可以快速释放。它还提供了直接访问数组的方法,通过 ByteBuf.array() 来获取 byte[]数据。示例如下:
ByteBuf heapBuf = ...;
if (heapBuf.hasArray()) { //1
byte[] array = heapBuf.array(); //2
int offset = heapBuf.arrayOffset() + heapBuf.readerIndex(); //3
int length = heapBuf.readableBytes();//4
handleArray(array, offset, length); //5
}
1.检查 ByteBuf 是否有支持数组。
2.如果这样得到的引用数组。
3.计算第一字节的偏移量。
4.获取可读的字节数。
5.使用数组,偏移量和长度作为调用方法的参数。
DIRECT BUFFER(直接缓冲区)
“直接缓冲区”是另一个 ByteBuf 模式。对象的所有内存分配发生在 堆,对不对?好吧,并非总是如此。在 JDK1.4 中被引入 NIO 的ByteBuffer 类允许一个 JVM 实现通过本地调用分配内存,其目的是:通过免去中间交换的内存拷贝, 提升IO处理速度; 直接缓冲区的内容可以驻留的正常垃圾回收以外。这就解释了为什么“直接缓冲区”是理想的 通过 socket 实现数据传输。如果你的数据是包含在堆中分配的缓冲区,JVM 实际上在通过 socket 发送之前将复制您的缓冲区到直接缓冲区。
但是直接缓冲区的缺点是在分配内存空间和释放内存时比堆缓冲区更复杂,另外一个缺点是如果是与传统的代码工作;因为数据不是在堆上,你可能要作出一个副本,如下:
ByteBuf directBuf = ...
if (!directBuf.hasArray()) { //1
int length = directBuf.readableBytes();//2
byte[] array = new byte[length]; //3
directBuf.getBytes(directBuf.readerIndex(), array); //4
handleArray(array, 0, length); //5
}
1.检查 ByteBuf 不是由数组支持。如果不是,这是一个直接缓冲区。
2.获取可读的字节数
3.分配一个新的数组来保存字节
4.字节复制到数组
5.调用一些数组,偏移量和长度的方法
显然,这涉及到比使用支持数组多做一些工作。因此,如果你知道事先在容器中的数据作为一个数组进行访问,你可能更愿意使用堆内存。
COMPOSITE BUFFER(复合缓冲区)
第三种也是最后一种模式使用的是复合缓冲区,它为多个 ByteBuf 提供一个聚合视图。在 这里你可以根据需要添加或者删除 ByteBuf 实例,这是一个 JDK 的 ByteBuffer 实现完全缺 失的特性。
Netty 通过一个 ByteBuf 子类——CompositeByteBuf——实现了这个模式,它提供了一 个将多个缓冲区表示为单个合并缓冲区的虚拟表示。
字节级操作
随机访问索引
ByteBuf buffer = ...;
for (int i = 0; i < buffer.capacity(); i++) {
byte b = buffer.getByte(i);
System.out.println((char)b);
}
网友评论