JDK 的 ByteBuffer 的缺点:
1.final byte[] hb; 这是 JDKde ByteBuffer 对象中用于存储数据的对象声明; 可以看到, 其字节数组是被声明为 final 的, 也就是长度是固定不变的, 一旦分配好后不能动态扩容与收缩; 而且当待存储的数据字节很大时就很有可能出现 IndexOutOfBoundsException, 如果需要预防这个异常, 就需要在存储之前完全确定好待存储的字节大小.
2.ByteBuffer 只使用一个 position 指针来标识位置信息, 在进行读写切换时就需要调用 flip 方法或是 rewind 方法, 使用起来很不方便.
0 <= mark <= position <= limit <= capacity
JDK 中 ByteBuffer 中的方法
flip()方法
1. 将 limit 值设为当前的 position
2. 将 position 设为 0.
clear()方法
1. 将 limit 值设为 capacity.
2. 将 position 值设为 0.
compact()方法
1. 将所有未读的数据复制到 buffer 起始位置处.
2. 将 position 设为最后一个未读元素的后面.
3. 将 limit 设为 capacity.
4. 现在 buffer 就准备好了, 但不会覆盖未读的数据.
Netty 针对此做了优化
1.Netty 的 ByteBuf 采用了读写索引分离的策略 (readerIndex 与 writerIndex), 一个初始化(里面尚未有任何数据) 的 ByteBuf 的 readerIndex 与 writerIndex 值都是 0.
2. 当读索引与写索引处于同一个位置时, 如果我们继续读取, 那么就会抛出 IndexOutOfBoundException.
3. 对于 ByteBuf 的任何读写分离操作都会分别单独维护读索引与写索引. maxCapacity 最大容默认的限制就是 Integer.Max_VALUE.
netty 本身提供 3 种缓冲区类型
- 1.heap buffer
- 2.direct buffer
- 3.composite buffer
- Heap buffer(堆缓存区)
这是最常用的类型, ByteBuf 将数据存储到 JVM 的堆缓冲区中, 并且将实际的数据存放到 byte array 中来实现
优点: 由于数据是存储在 JVM 堆中, 因此可以快速的创建与快速的释放, 并且它提供了直接访问内部字节数据的方法
缺点: 每次读写数据时, 都需要先将数据复制到直接缓存区中再进行网络传输
Direct Buffer(直接缓冲区)
在堆外直接分配内存空间, 直接缓冲区并不会占用堆的容量空间, 因为它是由操作系统在本地内存进行的数据分配.
优点: 在使用 Socket 进行数据传输时, 性能非常好, 因为数据直接位于操作系统的本地内存中, 所以不需要从 JVM 将数据复制到直接缓冲区中.
缺点: 因为 Direct Buffer 是直接在操作系统内存中的, 所以内存空间的分配与释放要比堆空间更加复杂, 而且速度要慢一些.
Netty 通过提供内存池来解决这个问题, 直接缓冲区并不支持通过字节数组来分配内存.
来源: http://www.bubuko.com/infodetail-3302518.html