Netty学习摘记 —— ByteBuf

本文参考

本篇文章是对《Netty In Action》一书第五章"ByteBuf"的学习摘记,主要内容为JDK 的ByteBuffer替代品ByteBuf的优越性

你可能注意到我跳过了第四章"传输",因为第四章主要是对各种传输类型的简单介绍和如何选择的说明,在之后的几个章节中,我们还会再碰到,如用于单元测试的Embedded传输

ByteBuf工作方式

ByteBuf provides two pointer variables to support sequential read and write operations readerIndex for a read operation and writerIndex for a write operation respectively. The following diagram shows how a buffer is segmented into three areas by the two pointers:

+------------------------------+----------------------------+-----------------------------+
| discardable bytes | readable bytes | writable bytes |
| | (CONTENT) | |
+------------------------------+----------------------------+-----------------------------+
| | | |
0 <= readerIndex <= writerIndex <= capacity

JDK 的ByteBuffer只有一个索引,必须调用flip()方法在读模式和写模式之间进行切换,而ByteBuf 维护了两个不同的索引:一个用于读取,一个用于写入,两个索引将缓冲区划分成 3 部分。从 ByteBuf 读取时, readerIndex 将会被递增已经被读取的字节数。同样地,写入 ByteBuf 时, writerIndex 也会被递增

如果打算读取字节直到 readerIndex 达到和 writerIndex 同样的值时会发生什么?在那时,我们将会到达"可以读取的"数据的末尾。ByteBuf和数组有诸多相似之处,就如同试图读取超出数组末尾的数据一样,试图读取超出该点的数据将会触发一个 IndexOutOfBoundsException

Just like an ordinary primitive byte array, ByteBuf uses zero-based indexing. It means the index of the first byte is always 0 and the index of the last byte is always capacity - 1.

For example, to iterate all bytes of a buffer, you can do the following, regardless of its internal implementation:
for (int i = 0; i < buffer.capacity(); i ++) {
byte b = buffer.getByte(i);
System.out.println((char) b);
}

上面的示例代码实现了随机访问索引,注意名称以 read 或者 write 开头的 ByteBuf 方法,将会推进其对应的索引,而名称以 set 或者 get 开头的操作则不会

可以指定 ByteBuf 的最大容量。试图移动写索引(即 writerIndex)超过这个值将会触发一个异常(默认的限制是 Integer.MAX_VALUE)

 

discardable bytes可丢弃字节

上图标记为可丢弃字节的分段包含了已经被读过的字节。通过调用 discardReadBytes()方法,可以丢弃它们并回收空间。这个分段的初始大小为 0,存储在readerIndex中, 会随着read操作的执行而增加(get操作不会移动readerIndex)

下图展示了缓冲区上调用discardReadBytes()方法后的结果。可以看到,可丢弃字节分段中的空间已经变为可写的了。注意,在调用discardReadBytes()之后,对可写分段的内容并没有任何的保证,因为只是移动了可以读取的字节以及writerIndex,而没有对所有可写入的字节进行擦除写

BEFORE discardReadBytes()

+----------------------------+----------------------+----------------------+
| discardable bytes | readable bytes | writable bytes |
+---------------------------+-----------------------+----------------------+
| | | |

0 <= readerIndex <= writerIndex <= capacity


AFTER discardReadBytes()

+-----------------------+------------------------------------------------+
| readable bytes | writable bytes (got more space) |
+-----------------------+------------------------------------------------+
| | |

readerIndex (0) <= writerIndex (decreased) <= capacity

 

Please note that there is no guarantee about the content of writable bytes after calling discardReadBytes(). The writable bytes will not be moved in most cases and could even be filled with completely different data depending on the underlying buffer implementation.

注意不要频繁地调用 discardReadBytes()方法使得可写分段最大化,这极有可能会导致内存复制,因为可读字节(图中标记为 CONTENT 的部分)必须被移动到缓冲区的开始位置。我们建议只在有真正需要的时候才这样做,例如,当内存非常宝贵的时候

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自www.cnblogs.com/kuluo/p/12624889.html