本節開始學習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分類
- 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);
}