本节开始学习netty的内存分配机制,搜先是ByteBuf。
作为一个容器,源码中的如下。有三块区域
- discardable bytes:无效空间(已经读取过的空间),可丢弃字节的区域,由
readerIndex
指针控制 - readable bytes:内容空间,可读字节的区域,由
readerIndex
和writerIndex
指针控制控制 - writable bytes:空闲空间,可写入字节的区域,由
writerIndex
指针和capacity
容量控制
* <pre>
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* | | (CONTENT) | |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
* </pre>
-
ByteBuf
还定义了抽象方法maxCapacity
,用于子类可增加一个最大容量的指针。
public abstract int maxCapacity();
- ByteBuf定义了丰富的api,主要是读写和设置以及一些指针和容量的操作,详情参考《ByteBuf 主要API》
- 读逻辑在
AbstractByteBuf
骨架类,主要就是操作readerIndex指针,而具体怎么读着交给具体子类实现,暴露_getByte(i);
给子类即可。
@Override
public byte readByte() {
checkReadableBytes0(1);
int i = readerIndex;
byte b = _getByte(i);
readerIndex = i + 1;
return b;
}
- 写逻辑在
AbstractByteBuf
骨架类,把当前的值写到ByteBuf里面,擦欧总writerIndex指针,并且暴露_setByte(writerIndex++, value);
给子类去具体实现写逻辑
@Override
public ByteBuf writeByte(int value) {
ensureWritable0(1);
_setByte(writerIndex++, value);
return this;
}
-
ByteBuf分类
ByteBuf家族
- pooled和unpooled
Pooled:每次都从预先分配好的内存中去取出一段连续内存封装成一个ByteBuf给应用程序使用
Unpooled:每次分配内存的时候,直接调用系统api,向操作系统申请一块内存
- Unsafe和非Unsafe
jdk中有Unsafe对象可以直接拿到对象的内存地址,并且基于这个内存地址进行读写操作。那么对应的分类的区别就是是否可以拿到jdk底层的Unsafe进行读写操作了。
- 跟进
PooledUnsafeHeapByteBuf
@Override
protected byte _getByte(int index) {
//memory:内存首地址
//idx(index):偏移量
return UnsafeByteBufUtil.getByte(memory, idx(index));
}
static byte getByte(byte[] array, int index) {
return PlatformDependent.getByte(array, index);
}
public static byte getByte(byte[] data, int index) {
return PlatformDependent0.getByte(data, index);
}
static byte getByte(byte[] data, int index) {
//通过UNSAFE去获取
return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
}
- 跟进
PooledHeapByteBuf
@Override
protected byte _getByte(int index) {
return HeapByteBufUtil.getByte(memory, idx(index));
}
static byte getByte(byte[] memory, int index) {
//直接拿到一个数组
return memory[index];
}
- Head和Direct
Head:是调用jvm的堆内存进行分配的,需要被gc进行管理
Direct:是调用jdk的api进行内存分配,不受jvm控制,不会参与到gc的过程
1.跟进UnpooledHeapByteBuf
,Head其实就是维持了一个代表内存的数组
private final ByteBufAllocator alloc;
//依赖byte数组,所有内存相关的操作都在这.
//持有内存数组(堆)
byte[] array;
private ByteBuffer tmpNioBuf;
@Override
protected byte _getByte(int index) {
//直接传入内存数组
return HeapByteBufUtil.getByte(array, index);
}
static byte getByte(byte[] memory, int index) {
//直接拿到一个数组
return memory[index];
}
- 跟进
UnpooledDirectByteBuf
,Direct其实就是调用jdk的直接内存对象DirectByteBuffer
import java.nio.ByteBuffer;
private final ByteBufAllocator alloc;
//依赖jdk底层的ByteBuffer
private ByteBuffer buffer;
private ByteBuffer tmpNioBuf;
private int capacity;
private boolean doNotFree;
@Override
public byte getByte(int index) {
ensureAccessible();
return _getByte(index);
}
@Override
protected byte _getByte(int index) {
//使用buffer
return buffer.get(index);
}
网友评论