首先介紹些netty內(nèi)存池的層級(jí)結(jié)構(gòu),主要分為Arena、ChunkList、Chunk、Page、Subpage這5個(gè)層級(jí),這幾個(gè)層級(jí)的關(guān)系由大到小,如下圖所示:

Arena代表1個(gè)內(nèi)存區(qū)域,為了優(yōu)化內(nèi)存區(qū)域的并發(fā)訪問(wèn),netty中內(nèi)存池是由多個(gè)Arena組成的數(shù)組,分配時(shí)會(huì)每個(gè)線程按照輪詢(xún)策略選擇1個(gè)Arena進(jìn)行內(nèi)存分配。
1個(gè)Arena由兩個(gè)PoolSubpage數(shù)組和多個(gè)ChunkList組成。兩個(gè)PoolSubpage數(shù)組分別為tinySubpagePools和smallSubpagePools。多個(gè)ChunkList按照雙向鏈表排列,每個(gè)ChunkList里包含多個(gè)Chunk,每個(gè)Chunk里包含多個(gè)Page(默認(rèn)2048個(gè)),每個(gè)Page(默認(rèn)大小為8k字節(jié))由多個(gè)Subpage組成。
每個(gè)Arena由如下幾個(gè)ChunkList構(gòu)成:
- PoolChunkList<T> qInit:存儲(chǔ)內(nèi)存利用率0-25%的chunk
- PoolChunkList<T> q000:存儲(chǔ)內(nèi)存利用率1-50%的chunk
- PoolChunkList<T> q025:存儲(chǔ)內(nèi)存利用率25-75%的chunk
- PoolChunkList<T> q050:存儲(chǔ)內(nèi)存利用率50-100%的chunk
- PoolChunkList<T> q075:存儲(chǔ)內(nèi)存利用率75-100%的chunk
- PoolChunkList<T> q100:存儲(chǔ)內(nèi)存利用率100%的chunk
每個(gè)ChunkList里包含的Chunk數(shù)量會(huì)動(dòng)態(tài)變化,比如當(dāng)該chunk的內(nèi)存利用率變化時(shí)會(huì)向其它ChunkList里移動(dòng)。
每個(gè)Chunk里默認(rèn)包含2048個(gè)Page。
每個(gè)Page包含的Subpage的大小和個(gè)數(shù)由首次從該P(yáng)age分配的內(nèi)存大小決定,1個(gè)page默認(rèn)大小為8k,如果首次在該page中需要分配1k字節(jié),那么該page就被分為8個(gè)Subpage,每個(gè)Subpage大小為1k。
在PoolArena中申請(qǐng)內(nèi)存的流程圖如下:

- 對(duì)于小于pageSize大小的內(nèi)存,會(huì)在tinySubpagePools或smallSubpagePools中分配,tinySubpagePools用于分配小于512字節(jié)的內(nèi)存,smallSubpagePools用于分配大于512小于pageSize的內(nèi)存。
- 對(duì)于大于pageSize小于chunkSize大小的內(nèi)存,會(huì)在PoolChunkList的Chunk中分配。
- 對(duì)于大于chunkSize大小的內(nèi)存,直接創(chuàng)建非池化Chunk來(lái)分配內(nèi)存,并且該Chunk不會(huì)放在內(nèi)存池中重用。
對(duì)于在q050、q025、q000、qInit、q075這些PoolChunkList里申請(qǐng)內(nèi)存的流程圖如下:

- 在PoolChunk中,數(shù)組組織呈完美二叉樹(shù)數(shù)據(jù)結(jié)構(gòu)。二叉樹(shù)葉子節(jié)點(diǎn)為2048個(gè)Page,每個(gè)Page的父節(jié)點(diǎn)用于分配pageSize
*2大小內(nèi)存,同理,對(duì)于Page葉子節(jié)點(diǎn)的父節(jié)點(diǎn)的父節(jié)點(diǎn),用于分配pageSize*4大小的內(nèi)存,后面以此類(lèi)推。 - 在初始狀態(tài)時(shí),tinySubpagePools和smallSubpagePools為空,因此最初分配小于pageSize的內(nèi)存時(shí),需要新建1個(gè)PoolChunk來(lái)分配這塊小內(nèi)存,PoolChunk會(huì)對(duì)Page分類(lèi)成若干Subpage,然后用Subpage分配這塊小內(nèi)存,最后會(huì)把該Subpage放在tinySubpagePools或smallSubpagePools中。