Netty原始碼解析 -- 記憶體池與PoolArena
阿新 • • 發佈:2020-11-29
我們知道,Netty使用直接記憶體實現Netty零拷貝以提升效能,
但直接記憶體的建立和釋放可能需要涉及系統呼叫,是比較昂貴的操作,如果每個請求都建立和釋放一個直接記憶體,那效能肯定是不能滿足要求的。
這時就需要使用記憶體池。
即從系統中申請一大塊記憶體,再在上面分配每個請求所需的記憶體。
Netty中的記憶體池主要涉及PoolArena,PoolChunk與PoolSubpage。
本文主要分析PoolArena的作用與實現。
**原始碼分析基於Netty 4.1.52**
**介面關係**
ByteBufAllocator,記憶體分配器,負責為ByteBuf分配記憶體, 執行緒安全。
PooledByteBufAllocator,池化記憶體分配器,預設的ByteBufAllocator,預先從作業系統中申請一大塊記憶體,在該記憶體上分配記憶體給ByteBuf,可以提高效能和減小記憶體碎片。
UnPooledByteBufAllocator,非池化記憶體分配器,每次都從作業系統中申請記憶體。
RecvByteBufAllocator,接收記憶體分配器,為Channel讀入的IO資料分配一塊大小合理的buffer空間。具體功能交由內部介面Handle定義。
它主要是針對Channel讀入場景新增一些操作,如guess,incMessagesRead,lastBytesRead等等。
ByteBuf,分配好的記憶體塊,可以直接使用。
下面只關注PooledByteBufAllocator,它是Netty中預設的記憶體分配器,也是理解Netty記憶體機制的難點。
#### 記憶體分配
前面文章《ChannelPipeline機制與讀寫過程》中分析了資料讀取過程,
NioByteUnsafe#read
```
public final void read() {
...
final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
allocHandle.reset(config);
ByteBuf byteBuf = null;
...
byteBuf = allocHandle.allocate(allocator);
allocHandle.lastBytesRead(doReadBytes(byteBuf));
...
}
```
recvBufAllocHandle方法返回AdaptiveRecvByteBufAllocator.HandleImpl。(AdaptiveRecvByteBufAllocator,PooledByteBufAllocator都在DefaultChannelConfig中初始化)
AdaptiveRecvByteBufAllocator.HandleImpl#allocate -> AbstractByteBufAllocator#ioBuffer -> PooledByteBufAllocator#directBuffer -> PooledByteBufAllocator#newDirectBuffer
```
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
// #1
PoolThreadCache cache = threadCache.get();
P