Heap Buffer(堆缓冲区)
-
这是最长用的类型,ByteBuf将数据存储到JVM的堆空间中,并且将实际的数据存放到byte array中来实现。
-
优点:由于数据是存储在JVM的堆中,所以可以快速的创建和释放,并且他提供了直接访问内部字节数组的方法。
缺点:每次读写数据中,都需要先将数据复制到直接缓冲区中进行网络数据传输。
Direct Buffer(直接缓冲区)
在堆外直接分配缓内存空间,直接缓冲区并不会占用堆的内存空间,因为他是操作系统在本地内存进行分配的。
优点:在使用Socket进行传输数据的时候,性能非常好,因为数据直接位于操作系统的本地内存中,所以不需要从JVM复制到直接缓冲区中,性能很好。
缺点:因为Direct Buffer是直接在操作系统内存中的,所以内存空间的分配与释放要比堆内空间更加复杂,而且速度也慢
Netty通过提供内存池来解决这个问题。直接缓冲区并不支持通过字节数组的方式来访问数据。
对于后端的业务消息的编解码,推荐使用HeapByteBuf;对于I/O通信线程读写缓冲区中,推荐使用DirectByteBuf
Composite buffer(复合缓冲区)
public static void main(String[] args) {
CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
ByteBuf heapBuf = Unpooled.buffer();
ByteBuf directBuf = Unpooled.directBuffer();
compositeByteBuf.addComponents(heapBuf,directBuf);
compositeByteBuf.removeComponent(0);
Iterator<ByteBuf> iterator = compositeByteBuf.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
compositeByteBuf.forEach(System.out::println);
}
JDK的ByteBuffer与Netty的ByteBuf差异对比
- Netty的ByteBuf采用了读写所以分离的策略(readerIndex与writerIndex),一个初始化(没有数据)的ByteBuf的readerIndex和writerIndex都为0;
- 当读索引和写索引处于同一个位置的时候,如果我们继续读取,那么就会抛出IndexOutofBoundsException;
- 对于ByteBuf的任何读写操作,都会分别单独维护读索引和写索引。
JDK的ByteBuffer的缺点:
- final byte[] hb;用于存储数据的对象声明;可以看到,其字节数组是被声明为final的,也就是固定不变的长度。一旦分配好后,不能动态扩容与收缩;而且当待存储的数据字节很大时,容易数组越界。如果ByteBuffer空间不足,我们只有一种解决方案,就是创建一个全新的ByteBuffer对象,再将之前的拷贝过去。
- ByteBuffer只使用一个position指针来表示位置信息,在进行读写切换的时候就需要调用flip方法或者rewind方法,使用起来很不方便。
Netty的ByteBuf的优点:
- 存储字节的数组是动态的,其最大值默认是整数最大值。这里的动态性体现在write方法中的,会自动判断容量,如果不足,自动扩容。
- ByteBuf读写索引是分开的,使用起来很方便。
网友评论