自頂向下深入分析Netty(十)--JEMalloc分配算法

1. JEMalloc分配算法

Netty的PooledByteBuf采用與jemalloc一致的內存分配算法。可用這樣的情景類比,想像一下當前電商的配送流程。當顧客采購小件商品(比如書籍)時,直接從同城倉庫送出;當顧客采購大件商品(比如電視)時,從區域倉庫送出;當顧客采購超大件商品(比如汽車)時,則從全國倉庫送出。Netty的分配算法與此相似,可參見下圖:

jemalloc內存分配示意圖

稍有不同的是:在Netty中,小件商品和大件商品都首先從同城倉庫(ThreadCache-tcache)送出;如果同城倉庫沒有,則會從區域倉庫(Arena)送出。
對于商品分類,Netty根據每次請求分配內存的大小,將請求分為如下幾類:


分配請求分類

注意以下幾點:

  1. 內存分配的最小單位為16B。
  2. < 512B的請求為Tiny,< 8KB(PageSize)的請求為Small,<= 16MB(ChunkSize)的請求為Normal,> 16MB(ChunkSize)的請求為Huge。
  3. < 512B的請求以16B為起點每次增加16B;>= 512B的請求則每次加倍。
  4. 不在表格中的請求大小,將向上規范化到表格中的數據,比如:請求分配511B、512B、513B,將依次規范化為512B、512B、1KB。

1.1 Arena

為了提高內存分配效率并減少內部碎片,jemalloc算法將Arena切分為小塊Chunk,根據每塊的內存使用率又將小塊組合為以下幾種狀態:QINIT,Q0,Q25,Q50,Q75,Q100。Chunk塊可以在這幾種狀態間隨著內存使用率的變化進行轉移,內存使用率和狀態轉移可參見下圖:


Chunk塊內存使用率和轉移

其中橫軸表示內存使用率(百分比),縱軸表示狀態,可知:

  1. QINIT的內存使用率為[0,25)、Q0為(0,50)、Q100為[100,100]。
  2. Chunk塊的初始狀態為QINIT,當使用率達到25時轉移到Q0狀態,再次達到50時轉移到Q25,依次類推直到Q100;當內存釋放時又從Q100轉移到Q75,直到Q0狀態且內存使用率為0時,該Chunk從Arena中刪除。注意極端情況下,Chunk可能從QINIT轉移到Q0再釋放全部內存,然后從Arena中刪除。

1.2 Chunk和Page

雖然已將Arena切分為小塊Chunk,但實際上Chunk是相當大的內存塊,在jemalloc中建議為4MB,Netty默認使用16MB。為了進一步提高內存利用率并減少內部碎片,需要繼續將Chunk切分為小的塊Page。一個典型的切分將Chunk切分為2048塊,Netty正是如此,可知Page的大小為:16MB/2048=8KB。一個好的內存分配算法,應使得已分配內存塊盡可能保持連續,這將大大減少內部碎片,由此jemalloc使用伙伴分配算法盡可能提高連續性。伙伴分配算法的示意圖如下:


伙伴分配算法

圖中最底層表示一個被切分為2048個Page的Chunk塊。自底向上,每一層節點作為上一層的子節點構造出一棵滿二叉樹,然后按層分配滿足要求的內存塊。以待分配序列8KB、16KB、8KB為例分析分配過程(每個Page大小8KB):

  1. 8KB--需要一個Page,第11層滿足要求,故分配2048節點即Page0;
  2. 16KB--需要兩個Page,故需要在第10層進行分配,而1024的子節點2048已分配,從左到右找到滿足要求的1025節點,故分配節點1025即Page2和Page3;
  3. 8KB--需要一個Page,第11層滿足要求,2048已分配,從左到右找到2049節點即Page1進行分配。

分配結束后,已分配連續的Page0-Page3,這樣的連續內存塊,大大減少內部碎片并提高內存使用率。

1.3 SubPage

Netty中每個Page的默認大小為8KB,在實際使用中,很多業務需要分配更小的內存塊比如16B、32B、64B等。為了應對這種需求,需要進一步切分Page成更小的SubPage。SubPage是jemalloc中內存分配的最小單位,不能再進行切分。SubPage切分的單位并不固定,以第一次請求分配的大小為單位(最小切分單位為16B)。比如,第一次請求分配32B,則Page按照32B均等切分為256塊;第一次請求16B,則Page按照16B均等切分為512塊。為了便于內存分配和管理,根據SubPage的切分單位進行分組,每組使用雙向鏈表組合,示意圖如下:


Subpage雙向鏈表

其中每組的頭結點head只用來標記該組的大小,之后的節點才是實際分配的SubPage節點。需要注意的是,這些節點正是上一節中滿二叉樹的葉子節點即一個Page。

至此,已介紹完jemalloc的基本思想,關于具體實現細節,可跳轉:

  1. PoolArena
  2. PoolChunk
  3. PoolChunkList
  4. PoolSubpage
  5. PooThreadCache
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容