TCMalloc的使用與原始碼剖析之三---------TCMalloc的記憶體分配的主要層次
(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
該層的分配需要鎖。CentralCache和ThreadCache之間的空閒連結串列是一一對應的,以子連結串列為單位(obj個數很可能為num_objects_to_move(cl),見do_malloc與do_free流程圖)進行互相交換。
CentralCache的記憶體從PageHeap裡獲得。從PageHeap獲得的記憶體叫Span。一個Span在使用時只能用於同一大小的空閒連結串列,一但CentralCache從PageHeap中獲取新的Span,這個Span就是一個串好的相同大小記憶體的空閒連結串列。
Centralcache中有幾個重要資料結構:
1. TCEntry tc_slots_[kMaxNumTransferEntries];
tc_slots_每個節點存放的是一組obj連結串列,這一組obj的個數為num_objects_to_move,TCEntry結構體有兩指標,分別指向這個連結串列的頭和尾。
tc_slots_存放的是threadCache向CentralCache歸還的obj連結串列,並且只有當個數滿足num_objects_to_move時,才會放入tc_slots_。否則歸還的obj根據其所處的span,進行歸還,若對應的span是empty,那麼由於此時被歸還記憶體了,所以其有空閒obj了,便把該span從empty佇列清除,把其加入nonempty佇列。
2. span empty
FetchFromSpans函式把一個obj從nonempty佇列中的一個span中切出,準備給threadCache。當切完這個obj後,如果該span已經沒有記憶體空間了,那麼便把該span從nonempty佇列移除,並加入empty佇列。
3. span nonempty
CentralCache從中央頁堆申請頁面,中央頁堆以span的形式返回。在CentralCache中會把該span切成大小為class_to_size的obj,並把所有的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)第四層,系統頁面分配,
這就是呼叫系統函式了。
相關文章
- tcmalloc的工作原理
- TCmalloc
- tcmalloc的工作原理(一)
- 圖解 TCMalloc圖解
- new、delete、記憶體分配 的底層原理delete記憶體
- 物件的建立與記憶體分配物件記憶體
- JVM的藝術-物件建立與記憶體分配機制深度剖析JVM物件記憶體
- Oracle的記憶體分配和使用Oracle記憶體
- 記憶體的分配與釋放,記憶體洩漏記憶體
- Oracle記憶體分配與使用(zt)Oracle記憶體
- C++動態記憶體管理與原始碼剖析C++記憶體原始碼
- MySQL • 原始碼分析 • 記憶體分配機制MySql原始碼記憶體
- 記憶體分配的確定記憶體
- weblogic的記憶體分配Web記憶體
- 垃圾收集器與記憶體分配策略_記憶體分配策略記憶體
- Netty原始碼—六、tiny、small記憶體分配Netty原始碼記憶體
- Java物件記憶體分配原理及原始碼分析Java物件記憶體原始碼
- 筆記-更深層次的瞭解iOS記憶體管理筆記iOS記憶體
- C語言的記憶體分配C語言記憶體
- go是如何分配記憶體的?Go記憶體
- 控制C++的記憶體分配C++記憶體
- 記憶體分配的隱藏成本記憶體
- C中的記憶體分配模型記憶體模型
- 視覺化分析js的記憶體分配與回收視覺化JS記憶體
- Oracle的記憶體的分配、回收[final]Oracle記憶體
- 【Mysql】使用jemalloc(或tcmalloc)最佳化MYSQL(安裝步驟)MySql
- spark 原始碼分析之十五 -- Spark記憶體管理剖析Spark原始碼記憶體
- 簡單理解動態記憶體分配和靜態記憶體分配的區別記憶體
- JVM GC 與 記憶體分配策略JVMGC記憶體
- Oracle記憶體分配與調整Oracle記憶體
- mimalloc記憶體分配程式碼分析記憶體
- Go記憶體分配和GC的理解Go記憶體GC
- oracle9i 的記憶體分配Oracle記憶體
- linux記憶體管理(一)實體記憶體的組織和記憶體分配Linux記憶體
- C++記憶體分配與物件構造的分離C++記憶體物件
- spark 原始碼分析之十六 -- Spark記憶體儲存剖析Spark原始碼記憶體
- JVM 之 記憶體分配與回收策略JVM記憶體
- Java記憶體區域與分配策略Java記憶體