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圖解
- new、delete、記憶體分配 的底層原理delete記憶體
- JVM的藝術-物件建立與記憶體分配機制深度剖析JVM物件記憶體
- 記憶體的分配與釋放,記憶體洩漏記憶體
- C++動態記憶體管理與原始碼剖析C++記憶體原始碼
- Netty原始碼—六、tiny、small記憶體分配Netty原始碼記憶體
- 垃圾收集器與記憶體分配策略_記憶體分配策略記憶體
- C語言的記憶體分配C語言記憶體
- C中的記憶體分配模型記憶體模型
- 筆記-更深層次的瞭解iOS記憶體管理筆記iOS記憶體
- linux記憶體管理(一)實體記憶體的組織和記憶體分配Linux記憶體
- JVM GC 與 記憶體分配策略JVMGC記憶體
- Netty 中的記憶體分配淺析Netty記憶體
- Go記憶體分配和GC的理解Go記憶體GC
- spark 原始碼分析之十五 -- Spark記憶體管理剖析Spark原始碼記憶體
- mimalloc記憶體分配程式碼分析記憶體
- GPU深度學習效能的三駕馬車:Tensor Core、記憶體頻寬與記憶體層次結構GPU深度學習記憶體
- spark 原始碼分析之十六 -- Spark記憶體儲存剖析Spark原始碼記憶體
- C程式記憶體的分配,const ,volatile,staticC程式記憶體
- [20191114]linux記憶體分配的討論.txtLinux記憶體
- javascript堆疊記憶體分配的區別JavaScript記憶體
- MySQL 配置InnoDB的記憶體分配器MySql記憶體
- JVM 之 記憶體分配與回收策略JVM記憶體
- Java記憶體區域與分配策略Java記憶體
- 剖析記憶體中的程式之祕記憶體
- JVM快速調優手冊v1.0之三:記憶體分配策略JVM記憶體
- 一個可以參考的JVM記憶體分配JVM記憶體
- Tensorflow2對GPU記憶體的分配策略GPU記憶體
- 垃圾收集機制與記憶體分配策略記憶體
- JVM——垃圾收集器與記憶體分配JVM記憶體
- 垃圾回收與記憶體分配——總結篇記憶體
- 淺談JVM記憶體分配與垃圾回收JVM記憶體
- 垃圾收集器與記憶體分配策略記憶體
- C++ 類的記憶體分配是怎麼樣的?C++記憶體
- 動態記憶體分配記憶體
- Netty原始碼解析 -- 記憶體池與PoolArenaNetty原始碼記憶體
- with as 語句真的會把資料存記憶體嘛?(原始碼剖析)記憶體原始碼
- Go高階特性 14 | 記憶體分配:new 和 make 的使用場景Go記憶體