首先要清楚 Buffer 和 Cache 的区别。
???
- ByteBuf
- ByteBufHolder
- ByteBufAllocator
ByteBuf
在JDK中缓冲区可以理解为只有一个 position
指针用于读&写,详情可以参考 文章,与JDK不同的是 Netty 中缓冲区具有两个指示位置的指针分别用于 读|写:
-
readerIndex
读操作时,该值增加 -
writerIndex
写操作时,该值增加
初始状态这两个指针都指向位置 0
,通常 read
write
操作会自动的增加这两个指针值,get
set
这类相对位置的操作则不会改变指针值。
当然 ByteBuf 会有一个 maximum
用来标示缓冲区的最大容量,默认情况下为 Integer.MAX_VALUE
。
Netty 中缓冲区有3种类型:
- Heap Buffer
- Direct Buffer
- Composite Buffer
Heap Buffer 堆缓冲区
HeapBuffer 也是最常用的 ByteBuf,顾名思义,它的数据存储空间分配在 JVM 的堆内存区域。实际上是一个内部数组,并且 HeapBuffer 是可以访问其内部数组的。
访问 non-heap(非堆内存数组)时会导致
UnsupportedOperationException
,所以在访问 ByteBuf 内部数组时,需要通过hasArray()
来检验。
ByteBuf heapBuf = Unpooled.copiedBuffer("Netty IO", Charset.forName("UTF-8"));
if (heapBuf.hasArray()) {
System.out.println("Has Array");
byte[] array = heapBuf.array();
int offset = heapBuf.arrayOffset();
int length = heapBuf.readableBytes();
System.out.println("offset="+ offset +" length="+length);
System.out.println("capacity=" + heapBuf.capacity());
System.out.println("isDirect=" + heapBuf.isDirect());
System.out.println("isReadable=" + heapBuf.isReadable());
System.out.println("isReadOnly=" + heapBuf.isReadOnly());
} else {
System.out.println("Hasn't Array");
}
Direct Buffer 直接缓冲区
直接缓冲区指的是内存空间不在堆空间上,而是直接在内存上分配的。
在进行 Socket 数据传输的时候,使用直接缓冲区是一个不错的选择,因为如果使用的是非直接缓冲区的话,JVM需要先把缓冲区拷贝到直接缓冲区,然后再进行 Socket 传输。
其缺点在于:
- 直接缓冲区的内存分配和回收代价会比堆内缓冲区要高。(这也是为什么 Netty 会支持缓冲池的原因)
- 使用直接缓冲区的话,我们就无法像操作堆缓冲区一样来直接操作其内部数组了。
ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer();
directBuf.writeBytes("Netty IO".getBytes());
if (!directBuf.hasArray()) {
System.out.println("No Array");
int length = directBuf.readableBytes();
byte[] copyArray = new byte[length];
directBuf.getBytes(0,copyArray);
System.out.println((char)copyArray[0]);
} else {
System.out.println("Has Array");
}
Composite Buffer 复合缓冲区
复合缓冲区实际上是将多个缓冲区实例组合起来,并向外提供一个统一视图。像是一个缓冲区的 List。
因为符合缓冲区只是多个缓冲区的视图,所以缓冲区的 hasArray() 方法将会返回 false。
ByteBuf heapBuf = Unpooled.copiedBuffer("Heap", Charset.forName("UTF-8"));
ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer().writeBytes("Direct".getBytes());
CompositeByteBuf compositeBuf = ByteBufAllocator.DEFAULT.compositeBuffer();
compositeBuf.addComponent(heapBuf);
compositeBuf.addComponent(directBuf);