TCMalloc 內存分配原理簡析


一、TCMalloc

TCMalloc簡介

為啥要介紹 TCMalloc
因為golang的內存分配算法絕大部分都是來自 TCMalloc,golang只改動了其中的一小部分。所以要理解golang內存分配算法,就要先了解下TCMalloc,為后面分析golang內存做一做功課。

tcmalloc 是google開發的內存分配算法庫,最開始它是作為google的一個性能工具庫 perftools 的一部分。TCMalloc是用來替代傳統的malloc內存分配函數。它有減少內存碎片,適用於多核,更好的並行性支持等特性。
前面TC就是Thread Cache兩英文的簡寫。

它提供了很多優化,如:

  • TCMalloc用固定大小的page(頁)來執行內存獲取、分配等操作。這個特性跟Linux物理內存頁的划分是不是有同樣的道理。
  • TCMalloc用固定大小的對象,比如8KB,16KB 等用於特定大小對象的內存分配,這對於內存獲取或釋放等操作都帶來了簡化的作用。
  • TCMalloc還利用緩存常用對象來提高獲取內存的速度。
  • TCMalloc還可以基於每個線程或者每個CPU來設置緩存大小,這是默認設置。
  • TCMalloc基於每個線程獨立設置緩存分配策略,減少了多線程之間鎖的競爭。

TCMalloc架構簡圖

來自:google tcmalloc design

  • Front-end:
    它是一個內存緩存,提供了快速分配和重分配內存給應用的功能。它主要有2部分組成:Per-thread cache 和 Per-CPU cache。

  • Middle-end:
    職責是給Front-end提供緩存。也就是說當Front-end緩存內存不夠用時,從Middle-end申請內存。它主要是 Central free list 這部分內容。

  • Back-end:
    這一塊是負責從操作系統獲取內存,並給Middle-end提供緩存使用。它主要涉及 Page Heap 內容。

TCMalloc將整個虛擬內存空間划分為n個同等大小的Page。將n個連續的page連接在一起組成一個Span。
PageHeap向OS申請內存,申請的span可能只有一個page,也可能有n個page。

ThreadCache內存不夠用會向CentralCache申請,CentralCache內存不夠用時會向PageHeap申請,PageHeap不夠用就會向OS操作系統申請。

TCMalloc中的概念

Page

操作系統對內存管理的單位,TCMalloc也是以頁為單位管理內存,但是TCMalloc中Page大小是操作系統中頁的倍數關系。2,4,8 ....

Span

Span 是PageHeap中管理內存頁的單位,它是由一組連續的Page組成,比如2個Page組成的span,多個這樣的span就用鏈表來管理。當然,還可以有4個Page組成的span等等。

ThreadCache

ThreadCache是每個線程各自獨立擁有的cache,一個cache包含多個空閑內存鏈表(size classes),每一個鏈表(size-class)都有自己的object,每個object都是大小相同的。

CentralCache

CentralCache是當ThreadCache內存不足時,提供內存供其使用。它保持的是空閑塊鏈表,鏈表數量和ThreadCache數量相同。ThreadCache中內存過多時,可以放回CentralCache中。

PageHeap

PageHeap保存的也是若干鏈表,不過鏈表保存的是Span(多個相同的page組成一個Span)。CentralCache內存不足時,可以從PageHeap獲取Span,然后把Span切割成object。

小對象內存分配 ThreadCache

TCMalloc 定義了很多個size class,每個size class都維護了一個可分配的的空閑列表,空閑列表中的每一項稱為一個object(如下圖),同一個size-class的空閑列表中每個object大小相同。
在申請小內存時(小於256K),TCMalloc會根據申請內存大小映射到某個size-class中。
比如,申請0到8個字節的大小時,會被映射到size-class1中,分配8個字節大小;申請9到16字節大小時,會被映射到size-class2中,分配16個字節大小….以此類推。

上面每一個object都是 N bytes。用於Thread Cache小內存分配。
這個就組成了每一個ThreadCache的free list,thread可以從各自的free list獲取對象,不需要加鎖,所以速度很快。

如果ThreadCache的free list為空呢?那就從CentralCache中的CentralFreeList中獲取若干個object到ThreadCache對應的size class列表中,然后在取出其中一個object返回。
如果CentralFreeList中的object不夠用了呢?那CentralFreeList就會向PageHeap申請一連串由Span組成頁面,並將申請的頁面切割成一系列的object之后,再將部分object轉移給ThreadCache。
如果PageHeap也不夠用了呢?那就向OS操作系統申請內存。
從上面論述可以看出,這也是一個多級緩存思想的應用。

當申請的內存大於256K時,不在通過ThreadCache分配,而是通過PageHeap直接分配大內存。

大對象內存分配 PageHeap

PageHeap負責向操作系統申請內存。
tcmalloc也是基於頁的分配方式,即每次申請至少一頁(page)的內存大小。tcmalloc中一頁大小為8KB(默認,可設置),多數linux中一頁為4KB,tcmallo的一頁是linux一頁大小的2倍。

PageHeap申請內存時按照頁申請,但它管理分配好的page內存時的基本單位是Span,Span對象代表了連續的頁。如下圖所示:

PageHeap中是如何組織Span,如下圖

Middle end-Central Free List

CentralFreeList是CentralCahe中,它的作用就是從PageHeap中取出部分Span,然后按照預定大小將其拆分成固定大小的object,提供給ThreadCache使用。

[完]

二、參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM