1. 程式人生 > >Netty原始碼解析 -- 記憶體池與PoolArena

Netty原始碼解析 -- 記憶體池與PoolArena

我們知道,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