TCMalloc的使用與原始碼剖析之三---------TCMalloc的記憶體分配的主要層次

hs-wu發表於2016-10-22

1)第一層,執行緒區域性分配,ThreadCache

       ThreadCache包含了一個不同物件大小的空閒連結串列陣列,其實現採用作業系統的執行緒區域性儲存功能。分配時幾乎不需要用鎖,除非觸發CentralCache的操作。

ThreadCache中的重要資料結構:


pthread_t     tid_;   繫結執行緒,達到每個執行緒有個緩衝池的目的

FreeList      list_[kNumClasses];  這個陣列就是上圖中的第一列,如下圖

 

陣列中的每一個節點就是代表上圖中的每一行,如下圖


每個class對應多大的記憶體空間?這個表示每組的大小的變數在哪裡?

不存在這樣的變數,但是通過對映關係可以達到一個class管一類size的作用,

如下圖所示,由cl 得到list_[cl],這也即是一個class


至於cl,是由class_array_得到的,關於這個內容在第五章:幾個重要的資料結構

若申請的記憶體是13位元組,但分配的卻是15位元組,那麼便會有2個位元組的記憶體碎片(內部碎片)。

2)第二層 ,中心分配,Centralcache

該層的分配需要鎖。CentralCacheThreadCache之間的空閒連結串列是一一對應的,以子連結串列為單位(obj個數很可能為num_objects_to_movecl),見do_mallocdo_free流程圖)進行互相交換。

CentralCache的記憶體從PageHeap裡獲得。從PageHeap獲得的記憶體叫Span。一個Span在使用時只能用於同一大小的空閒連結串列,一但CentralCachePageHeap中獲取新的Span,這個Span就是一個串好的相同大小記憶體的空閒連結串列。

Centralcache中有幾個重要資料結構:

1.     TCEntry  tc_slots_[kMaxNumTransferEntries];

tc_slots_每個節點存放的是一組obj連結串列,這一組obj的個數為num_objects_to_moveTCEntry結構體有兩指標,分別指向這個連結串列的頭和尾。

tc_slots_存放的是threadCacheCentralCache歸還的obj連結串列,並且只有當個數滿足num_objects_to_move時,才會放入tc_slots_。否則歸還的obj根據其所處的span,進行歸還,若對應的spanempty,那麼由於此時被歸還記憶體了,所以其有空閒obj了,便把該spanempty佇列清除,把其加入nonempty佇列。

2.      span empty

FetchFromSpans函式把一個objnonempty佇列中的一個span中切出,準備給threadCache。當切完這個obj後,如果該span已經沒有記憶體空間了,那麼便把該spannonempty佇列移除,並加入empty佇列。

3.     span nonempty

CentralCache從中央頁堆申請頁面,中央頁堆以span的形式返回。在CentralCache中會把該span切成大小為class_to_sizeobj,並把所有的obj連結起來,連結串列頭為span->objects。再把該連結串列加入nonempty佇列。

Nonempty佇列另外一個被加入span的地方在記憶體從threadCache歸還給CentralCache時,具體情況見上面”tc_slots_”這一資料結構的描述。

 

3第三層,中央頁堆,PageHeap

       PageHeap以一定數量連續頁面記憶體的形式提供記憶體。這組連續的頁面由一個Span物件描述,Span物件和它描述的頁面記憶體是獨立的。Span物件儲存了頁面的id序列,頁面id左移一個page就是記憶體的地址。由於頁面和Span記憶體獨立,需要用page id反向對映查詢Span物件就需要單獨的對映表。這個表用radix tree實現,兼顧效率和記憶體。PageHeap還負責合併和拆分相鄰的Span

PageHeap重要資料結構:

SpanList   large_;

SpanList   free_[kMaxPages];

中央頁堆是由空閒記憶體列表組成的陣列。對於i< 256而言,陣列的第k個元素是一個由每個單元是由k個頁面組成的空閒記憶體連結串列(這也即是free_)。第256個條目(這即是large_)則是一個包含了長度>= 256個頁面的空閒記憶體連結串列:


SpanList

struct SpanList {

    Span       normal;

    Span       returned;

  };

Returned代表的是已經歸還給系統的span

 

4)第四層,系統頁面分配,

這就是呼叫系統函式了。

相關文章