Buffer(缓冲区)
Buffer是缓冲区的抽象类,他定义了缓冲区的读写模式。
主要属性
- position:读写指针的位置
- mark: 标记位置
- limit:读写界限(超出不可读写)
- capacity:缓冲区最大容量(不可更改)
读写模式
因为缓冲区的只有一个指针(position),所以他需要有方法在读写模式之间切换
- 写模式切换到读模式 - 在写完数据后,调用flip(),然后即可读取数据
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
- 读模式切换到写模式 - 在读取完数据后,调用clear() ,可覆盖写入
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
- 标记重置模式,mark()与reset()配合使用,可实现重置指针的功能(读写)
public final Buffer mark() {
mark = position;
return this;
}
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
- 倒带(重读或者重写)
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
ByteBuffer
字节缓冲区的抽象类,子类有以堆内存做缓冲区的HeapByteBuffer和以堆外的系统本地内存做缓冲区的DirectByteBuffer
主要属性
除了父类的四个属性外,ByteBuffer还新增了三个属性
- hb:用来存储的字节数组
- offset:对于字节数组的起始偏移量(这个属性可以使用同一个字节数组封装两个独立的ByteBuffer,每个ByteBuffer的容量是字节数组长度的一半)
- isReadOnly:是否只读
主要方法
- 生成缓冲区
// 返回一个直接缓冲区
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
// 返回一个堆内存缓冲区
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
//把一个二进制数组包装成堆内存缓冲区
public static ByteBuffer wrap(byte[] array, int offset, int length)
{
try {
return new HeapByteBuffer(array, offset, length);
} catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException();
}
}
- 副本与分片(与原缓冲区内容共享,只是有各自独立的指针和标记)
// 返回一个从当前position指针位置开始的分片,重置指针和标记
public abstract ByteBuffer slice();
// 返回一个读写副本
public abstract ByteBuffer duplicate();
// 返回一个只读副本
public abstract ByteBuffer asReadOnlyBuffer();
- 读写
// 从当前position指针 + 1位置读取一个字节
public abstract byte get();
// 向当前position指针 + 1位置写入一个字节
public abstract ByteBuffer put(byte b);
// 从指定指针位置index处读取一个字节
public abstract byte get(int index);
//向指定指针index位置写入一个字节
public abstract ByteBuffer put(int index, byte b);
//从当前指针处读取length长度的字节,写入目标数组
public ByteBuffer get(byte[] dst, int offset, int length) {
checkBounds(offset, length, dst.length);
if (length > remaining())
throw new BufferUnderflowException();
int end = offset + length;
for (int i = offset; i < end; i++)
dst[i] = get();
return this;
}
...
HeapByteBuffer和DirectByteBuffer(-XX:MaxDirectMemorySize参数来设置堆外内存的大小)
优缺点比较
- 创建和释放Direct Buffer的代价比Heap Buffer得要高
- 由于DirectByteBuffer省去了从对内存拷贝到本地内存的操作,所以在I/O操作中会更快
- 由于DirectByteBuffer是堆外内存,减少了对堆内存的使用(DirectByteBuffer对象本身很小),所以会对堆内存的垃圾回收有所改善
Netty
由于HeapByteBuffer和DirectByteBuffer各有优缺点,在netty中,通过内存池复用DirectByteBuffer的方式,改善了DirectByteBuffer创建和释放代价高的缺点,更有效的使用DirectByteBuffer