Netty源碼分析第5章(ByteBuf)---->第5節: directArena分配緩衝區概述

 

Netty源碼分析第五章: ByteBufhtml

 

第五節: directArena分配緩衝區概述數組

 

上一小節簡單分析了PooledByteBufAllocator中, 線程局部緩存和arean的相關邏輯, 這一小節簡單分析下directArena分配緩衝區的相關過程緩存

回到newDirectBuffer中:源碼分析

protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) { PoolThreadCache cache = threadCache.get(); PoolArena<ByteBuffer> directArena = cache.directArena; ByteBuf buf; if (directArena != null) { buf = directArena.allocate(cache, initialCapacity, maxCapacity); } else { if (PlatformDependent.hasUnsafe()) { buf = UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity); } else { buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity); } } return toLeakAwareBuffer(buf); }

獲取了directArena對象以後, 經過allocate方法分配一個ByteBuf, 這裏allocate方法是PoolArena類中的方法this

跟到allocate方法中:spa

PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) { PooledByteBuf<T> buf = newByteBuf(maxCapacity); allocate(cache, buf, reqCapacity); return buf; }

首先經過newByteBuf得到一個ByteBuf對象操作系統

再經過allocate方法進行分配, 這裏要注意, 這裏進行分配的時候是線程私有的directArena進行分配線程

咱們跟到newByteBuf方法中指針

由於是directArena調用的newByteBuf, 因此這裏會進入DirectArena類的newByteBuf中:netty

protected PooledByteBuf<ByteBuffer> newByteBuf(int maxCapacity) { if (HAS_UNSAFE) { return PooledUnsafeDirectByteBuf.newInstance(maxCapacity); } else { return PooledDirectByteBuf.newInstance(maxCapacity); } }

由於默認一般是有unsafe對象的, 因此這裏會走到這一步中PooledUnsafeDirectByteBuf.newInstance(maxCapacity)

經過靜態方法newInstance建立一個PooledUnsafeDirectByteBuf對象

跟到newInstance方法中:

static PooledUnsafeDirectByteBuf newInstance(int maxCapacity) { PooledUnsafeDirectByteBuf buf = RECYCLER.get(); buf.reuse(maxCapacity); return buf; }

這裏經過RECYCLER.get()這種方式拿到一個ByteBuf對象, RECYCLER實際上是一個對象回收站, 這部份內容會在後面的內容中詳細剖析, 這裏咱們只須要知道, 這種方式能從回收站中拿到一個對象, 若是回收站裏沒有相關對象, 則建立一個新

由於這裏有多是從回收站中拿出的一個對象, 因此經過reuse進行復用

跟到reuse方法中:

final void reuse(int maxCapacity) { maxCapacity(maxCapacity); setRefCnt(1); setIndex0(0, 0); discardMarks(); }

這裏設置了的最大可擴容內存, 對象的引用數量, 讀寫指針位置都重置爲0, 以及讀寫指針的位置標記也都重置爲0

咱們回到PoolArena的allocate方法中:

PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) { PooledByteBuf<T> buf = newByteBuf(maxCapacity); allocate(cache, buf, reqCapacity); return buf; }

拿到了ByteBuf對象, 就能夠經過allocate(cache, buf, reqCapacity)方法進行內存分配了

跟到allocate方法中:

private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) { //規格化
    final int normCapacity = normalizeCapacity(reqCapacity); if (isTinyOrSmall(normCapacity)) { int tableIdx; PoolSubpage<T>[] table; //判斷是否是tinty
        boolean tiny = isTiny(normCapacity); if (tiny) { // < 512 //緩存分配
            if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) { return; } //經過tinyIdx拿到tableIdx
            tableIdx = tinyIdx(normCapacity); //subpage的數組
            table = tinySubpagePools; } else { if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) { return; } tableIdx = smallIdx(normCapacity); table = smallSubpagePools; } //拿到對應的節點
        final PoolSubpage<T> head = table[tableIdx]; synchronized (head) { final PoolSubpage<T> s = head.next; //默認狀況下, head的next也是自身
            if (s != head) { assert s.doNotDestroy && s.elemSize == normCapacity; long handle = s.allocate(); assert handle >= 0; s.chunk.initBufWithSubpage(buf, handle, reqCapacity); if (tiny) { allocationsTiny.increment(); } else { allocationsSmall.increment(); } return; } } allocateNormal(buf, reqCapacity, normCapacity); return; } if (normCapacity <= chunkSize) { //首先在緩存上進行內存分配
        if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) { //分配成功, 返回
            return; } //分配不成功, 作實際的內存分配
 allocateNormal(buf, reqCapacity, normCapacity); } else { //大於這個值, 就不在緩存上分配
 allocateHuge(buf, reqCapacity); } }

這裏看起來邏輯比較長, 其實主要步驟分爲兩步

1.首先在緩存上進行分配, 對應步驟是:

  cache.allocateTiny(this, buf, reqCapacity, normCapacity)

  cache.allocateSmall(this, buf, reqCapacity, normCapacity)

  cache.allocateNormal(this, buf, reqCapacity, normCapacity)

2.若是在緩存上分配不成功, 則實際分配一塊內存, 對應步驟是

  allocateNormal(buf, reqCapacity, normCapacity)

在這裏對幾種類型的內存進行介紹:

以前的小節咱們介紹過, 緩衝區內存類型分爲tiny, small, 和normal, 其實還有種不常見的類型叫作huge, 那麼這幾種類型的內存有什麼區別呢, 實際上這幾種類型是按照緩衝區初始化空間的範圍進行區分的, 具體區分以下:

tiny類型對應的緩衝區範圍爲0-512B

small類型對應的緩衝區範圍爲512B-8K

normal類型對應的緩衝區範圍爲8K-16MB

huge類型對應緩衝區範圍爲大於16MB

簡單介紹下有關範圍的含義:

16MB對應一個chunk, netty是以chunk爲單位向操做系統申請內存的

8k對應一個page, page是將chunk切分後的結果, 一個chunk對應2048個page

8k如下對應一個subpage, subpage是page的切分, 一個page能夠切分多個subpage, 具體切分幾個須要根據subpage的大小而定, 好比只要分配1k的緩衝區, 則會將page切分紅8個subpage

以上就是directArena內存分配的大概流程和相關概念

 

上一節: PooledByteBufAllocator簡述

下一節: 命中緩存的分配

相關文章
相關標籤/搜索