色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

TCMalloc 的架構設計細節

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-09 10:18 ? 次閱讀

本節將專注于TCMalloc 的架構設計細節,來整體看一下TCMalloc 的設計特性。

主要的幾個特性如下:

  1. 高性能。大多數對象的分配和釋放都不需要產生太多的競爭,因為tcmalloc 維護了thread-cache 來提供當前線程的內存分配需求。所以,應用大多數的內存申請需求不會有鎖的競爭,而且在多核場景有較好的擴展性。
  2. 靈活的使用內存資源。用戶不使用的內存,tcmalloc會選擇服復用或者歸還操作系統
  3. 降低了每個請求的內存開銷。通過分配相同大小的page 降低內存使用的開銷,這在小對象場景較為有效。
  4. 內部信息統計開銷較低。能夠開啟細粒度的應用內存占用信息,來幫助用戶展示tcmalloc內部內存使用的細節。

如何使用

安裝tcmalloc,應用編譯加入 -ltcmalloc即可默認將glibc的malloc 替換為tcmalloc的malloc 。

架構概覽

前面的文章中在介紹整體的tcmalloc的時候已經介紹過了,大體分為三個部分:

圖片

  • Front-end,主要維護線程cache,用來為應用提供 快速分配以及釋放內存的需求。
  • Middle-end,主要負責為font-end 中的thread-cache 填充內存。
  • back-end,負責從os直接獲取內存。

需要注意的是front-end 的 thread-cache 可以在每一個cpu下維護 或者 每一個線程下維護,back-end` 則能夠支持大內存的pageheap管理,也能支持小內存的pageheap 管理。

接下來,我們進入每一個組件詳細看一下其設計細節。

1. TCMalloc Front-end

Front-end 提供了Cache ,能夠緩存一部分內存 用來分配給應用 ,也能夠持有應用釋放的內存。這個Cache 作為per-cpu/per-thread 存在,其同一時刻只能由一個線程訪問,所以本身不需要任何的鎖,這也是多線程下內存分配釋放高效的原因。

如果Front-end 持有的內存大小足夠,其能夠滿足應用線程任何內存需求。如果持有的內存為空了,那它會從 middle-end 組件請求一批內存頁進行填充。

Middle-end 是由 CentralFreeList 和 TransferCache 兩部分組成,后續會詳細介紹這兩個組件。

如果用戶請求的內存大小超過了front-end 本身能緩存的大小(大內存需求),或者middle-end 緩存的內存頁也被用盡了,那這個時候會直接讓從back-end分配內存給用戶。

Front-end 在 TCMalloc 的演進過程中有兩種類型的實現:

  1. 最開始的時候只支持 per-thread 的cache 模式,這也是TCMalloc 名字 Thread-Cacheing malloc的由來。然而這種場景會隨著用戶線程的大量增加,出現了一些內存問題:每個線程只能有極小的thread-cache,需要消耗較多的CPU資源來聚合每個線程的內存資源。
  2. 較新版本的TCMalloc 支持了 per-CPU 模式。這種模式下每一個邏輯CPU 會有自己的的thread-cache 用來為運行在這個cpu的現場分配內存。在x86系統上,每一個邏輯cpu 和 一個超線程等價,我們lscpu 命令看到的cpu core是包括超線程的個數在內的。

1.1 小對象和大對象的內存分配過程

針對小內存對象的分配,Front-end的cache 會按照其大小將其映射到 60-80個size-classes 中的一個,實際的內存分配會按照該大小對應的size-class 的大小進行分配,size-class也是front-end 分配內存的粒度。

比如12B 的對象會best-fit到16B 的size-class中。設置這么多的size-class 還是為了盡可能得降低內存的浪費,比如原本的內存分配粒度都是2的n次冪,那對于23字節的內存需求就需要分配一個32字節的內存區域,而在tcmalloc的size-class的配置中只需要分配24字節即可。

Tcmalloc 在編譯的時候可以配置 size-class 的 內存分配是按照多少 Bytes 對齊,比如指定了__STDCPP_DEFAULT_NEW_ALIGNMENT__ <= 8,那size-class 內部可選的內存大小配置就是 8bytes 對齊,即8 bytes的倍數。如果編譯時指定了大于 8bytes,那后續所有的 ::operator new 的內存申請都會按照 16 bytes 進行對齊。

對于大內存需求的對象來說,內存大小的需求超過kMaxSize 256K,則會直接從back-end 分配。因此,這一部分的內存需求不會緩存再 front-end 以及 middle-end 中,由back-end的page-heap 進行管理。對于大內存對象的實際內存分配會按照tcmalloc page size 進行對齊。

1.2 內存釋放過程

如果要釋放一個對象,編譯期間如果能夠知道這個對象的大小,編譯器會直接告訴分配器這個對象的大小。大多數的時候,編譯期間并不清楚對象的大小,會從pagemap中查找這個對象。如果這個對象是一個小內存對象,釋放的時候會告訴front-end cache進行管理,如果是一個超過kMaxSize 的對象,則會直接釋放給back-end 的 pageheap。

1.3 Per-CPU mode

Per-cpu mode 和 per-thread mode 是 tcmalloc 的font-end 主體部分的兩種模式。因為per-thread mode 受到系統進程的線程數的影響,在大量線程的情況下會讓每個thread-cache 只能夠處理一小部分的內存申請釋放需求,還會消耗大量的cpu 來 由middle-end 進行不同thread-cache 之間的內存遷移。

所以 tcmalloc 提供了優化版本的 per-cpu mode,即每一個邏輯核 維護一個 ‘cpu-cache’ ,用來處理運行在當前核的線程的內存申請/釋放需求。

大體形態如下:

圖片

Per-cpu mode 下會申請一個大內存塊(也可以稱為slab),這個slab 會被多個cpu共享,其中每一個cpu會 持有slab 的一部分內存,并在其上存儲一系列元數據管理對應線程的內存對象。

上圖中的cpu1 會管理 on slab 的綠色部分內存區域,在這一部分區域中會先存儲一些元數據和指針來管理不同大小的 size-classes 的內存對象。其中元數據中包含一個header指針 和 每一個size-class 的索引block。

每一個size-class 的header 指針數據結構會有指向某一種實際存儲內存對象的指針數組,即是一個數組,每一個元素是一個指針,總共是三個指針,分別指向這一種size-class 內存對象區域的起始地址塊,當前地址塊(后續分配這個size-class 大小對象的時候會從current 開始分配),最大地址。

每一個cpu 能夠緩存的內存大小是通過SetMaxPerCpuCacheSize 配置的,也就是當前font-end 能夠緩存的內存總大小取決去當前系統的cpu核心數,擁有更好核心數的機器使用tcmalloc 能夠緩存更多的內存。為了避免 perf-cpu 長時間持有內存,tcmalloc 允許通過MallocExtension::ReleaseCpuMemory 接口來 指定釋放某一個cpu的內存。

// 設置每一個cpu 能夠cache住的內存大小
void MallocExtension::SetMaxPerCpuCacheSize(int32_t value) {
#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS
if (MallocExtension_Internal_SetMaxPerCpuCacheSize == nullptr) {
return;
}

MallocExtension_Internal_SetMaxPerCpuCacheSize(value); // 實際的執行函數
#else
(void)value;
#endif
}

// 釋放某一個cpu cache的內存
size_t MallocExtension::ReleaseCpuMemory(int cpu) {
#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS
if (MallocExtension_Internal_ReleaseCpuMemory != nullptr) {
return MallocExtension_Internal_ReleaseCpuMemory(cpu);
}
#endif
return 0;
}

當每一個cpu cache 的內存被分配耗盡,想要從 middle-end 獲取內存來緩存更多的對象時,也需要考慮對size-class進行擴容。如果這個size-class 的內存分配需求還在持續增加,則這個size-class的容量會持續增加,直到達到這個size-class 容量的hard-code。

1.4 Per-thread mode

用戶可以指定使用某一個thread 的cache,也就是指定thread-local cache。小內存的申請和釋放會根據thread-cache的需求在middle-end 之間遷移。

每一個 thread-cache 內部 不同size-class 對象會各自構造一個單鏈表(如果有 n 個size-classes,也就會有對應 n 個單鏈表),類似如下圖:

圖片

分配某一個對應size-class 對象的時候,對應 size-class 鏈表對象會被從單鏈表移除(free-list),表示這個指針對應地址的內存可以被用戶使用。釋放對象的時候,則會將這個對象地址追加到thread-cache 管理的 size-class 的鏈表。

在這個過程中,如果thread-cache 管理的內存不夠,或者超限,則會從 middle-end 獲取更多的內存對象或者將多余的內存對象釋放給 middle-end。

對于per-thread caches來說,可以通過 MallocExtension::SetMaxTotalThreadCacheBytes 設置最大的可用內存大小。每一個線程有自己的最小的 thread-cache 大小 KMinThreadCacheSize 512K,如果當前線程內存申請需求較大,內存容量也會通過middle-end 將其他線程的可用內存遷移到當前線程。

通過 middle-end 來協調當前的thread-cache 內存,通過ThreadCache::Scavenge(); 進行。

如果當前線程退出,則會將自己的thread-cache 的內存返回給 middle-end。

1.5 per-cpu 和 per-thread 運行時內存管理算法對比

對于thread-cache 和 per-cpu cache來說,在應用程序運行的時候如果 front-end 的cache 內存太小,那就需要頻繁從 central-freelist 也就是 middle-end 中獲取內存;但如果太大,就會讓過多的內存被閑置。如何配置一個合理的 front-end cache 的大小,這里兩種模式都提供了動態配置 cache大小的算法。

  • Per-thread 模式下,cache 內部的最大存儲對象容量 達到當前最大閾值時就會從middle-end 獲取更多的對象,從而增大這個限制。降低最大限制的前提是發現了較多的未被使用的對象,則會將這一些對象根據需求還給middle-end。
  • Per-cpu 模式下,增加cache 容量的前提是當前cache 是否在頻繁的從 middle-end 獲取內存 以及 釋放內存交替,則需增加容量限制,有更多的空間來緩存這一些內存對象。降低容量限制的前提是發現有一些空閑容量長時間沒有被使用。

這里在代碼細節上有很多的設計,比如如何設置合理的空閑時間的長度?如何界定 內存申請是頻繁的?都是一些動態規劃的最優思想的設計,值得去探索代碼細節。

2. TCMalloc Middle-end

到此,font-end 部分大體設計描述完。從前面的設計中可以看到,middle-end 的作用在 per-cpu和per-thread 模式都有非常重要的作用。

Middle-end 的主要作用為 font-end 提供內存申請需求,并將空閑內存返回給 back-end。

Middle-end 的組成主要有 Transfer cache 和 Central free list。對于每一個size-class,都會有有一個各自的 transfer cache 和 central free list。這一些caches 會有自己的 mutex lock,所以對于這一些cache的訪問, 因為鎖粒度較低,則不會有過多的沖突,保證了訪問的性能。

2.1 Transfer Cache

當 front-end 請求內存 或者 釋放內存的時候,會先到達 transfer cache。

Transfer cache 會持有 一個數組指針進行內存的釋放 或者 將新的內存對象填充進來并返回給font-end。

Transfer cache 會將一個cpu/tthread 釋放的內存分配給另一個cpu/thread 對內存的需求,這個類似于內存池的 內存對象流動在兩個不同的cpu/threads 之間可以非常迅速。

2.2 Central Free List

Central free list 通過 span 數據結構來管理內存,一個span 可以管理一個或者多個tcmalloc page,span 數據結構會在下文詳細描述。

Font-end 如果從 central free list 請求一個或者多個內存對象的時候,central free list 會從span中提取對應大小的對象,如果此時span 沒有足夠的pages 返回,則會從back-end 請求更多的span。

當內存對象返回給central free list,則這一些對象會通過 pagemap 被映射到對應的span中進行管理,如果所有的對象都返回給span,這個span就可以被釋放給back-end.

2.3 Pagemap 和 Spans

tcmalloc 管理的堆內存會在編譯期間確定一個page-size,并將這么多內存映射為對應size的一個個page。一系列正在被使用的pages 可以被一個span 對象描述,一個span 對象可以管理一個大的內存對象,也可以按照size-class 管理多個小對象。

pagemap 則是用來查找一個內存對象屬于哪一個span的,或者申請一個指定size-class 的內存對象。pagemap 是一個 2層或者3層的 radix-tree。下圖展示了一個兩層的 page-map 如何管理 span的,其中 spanA 管理了2個page,spanB 管理了三個page。

圖片

Span 這個數據結構 在 middle-end中用來 管理回收的內存對象;在back-end 用來管理 對應大小的pages,負責給central-list 提供對應大小的span。

3. TCMalloc Backend

tcmalloc 的back-end 主要有三個工作線程:

  • 管理未使用的大塊內存區域
  • 負責從 os 中獲取內存,來滿足其他組件的內存需求
  • 負責將其他組件不需要返回的內存,還給os

還有兩個后端組件:

  1. legacy pageheap. 管理tcmalloc 的pages
  2. 管理大頁內存的 pageheap。用來提升應用程序大頁內存的申請需求,降低TLB的miss。

3.1 Legacy Pageheap

legacy pageheap 是一個數組的freelist,統一管理可用內存頁。數組的每一個節點是一個free list,也就是單鏈表。一般這個數組的大小 k < 256,對于第k 個數組元素來說,它的鏈表中的每一個節點都管理了 k 個pages。

圖片

如果想要申請 k 個pages,則直接查找這個數組的第k 個元素,從free list中取一個節點即可。如果這個free list是空的,那就查找下一個數組元素的free list,直到找到一個非空的free list。如果還是失敗,則直接mmap 獲取內存。

當一段連續的pages 被返回給了pageheap,則會根據當前pages 是否能夠形成一個連續的pages區域,然后串聯這一些pages 并根據page數量 添加到對應的free list中。

3.2 大頁場景分配器設計

針對hugepage 的分配器設計 是希望其能夠有效持有 hugepage 大小的內存塊,需要的時候能夠快速分配,不需要的時候也能在合理的內存占用情況下釋放給操作系統。

hugepage 在x86 系統上一般是2M 及 以上的大小,tcmalloc 的back-end 擁有三個不同的cache 來管理大頁內存的分配:

  1. filler cache。能夠持有hugepage ,并提供一些大頁內存的申請需求。類似于legacy pageheap,通過一些free lists 管理pages 那樣管理huge page,主要用于處理小于hugepage 大小的內存申請。
  2. region cache。用于大于hugepage 大小的內存申請,這個cache 允許分配多個連續的hugepage。
  3. hugepage cache。和region cache的功能有點重復,也是用于分配大于hugepage 的內存申請。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3037

    瀏覽量

    74151
  • 操作系統
    +關注

    關注

    37

    文章

    6856

    瀏覽量

    123447
  • 編譯
    +關注

    關注

    0

    文章

    659

    瀏覽量

    32913
  • malloc
    +關注

    關注

    0

    文章

    52

    瀏覽量

    73
收藏 人收藏

    評論

    相關推薦

    軟件架構設計教程

    軟件架構設計教程
    發表于 09-26 15:27

    【汽車電氣架構設計軟件】

    因工作需要,求整車電氣架構設計軟件——PREEvision(盜版),價格可議,WetChat/***,非誠勿擾
    發表于 04-18 14:20

    STM32軟件架構設計的意義

    STM32軟件架構1、架構設計的意義(1)應用代碼邏輯清晰,且避免代碼冗余;(2)代碼通用性,方便軟件高速、有效的移植;(3)各功能獨立,低耦合高內聚;2、總體架構圖3、結構層說明4、遵循規則5、優劣評估6、STM32實例說明
    發表于 08-04 07:23

    為何要進行嵌入式軟件架構設計?如何設計?

    為何要進行嵌入式軟件架構設計?如何進行嵌入式軟件架構設計?
    發表于 11-01 06:31

    對嵌入式系統中的架構設計的理解

    【閱讀這篇文章,你能了解到什么】1. 從事嵌入式開發12年的我,對架構設計的理解;2. 對嵌入式系統中的架構設計要刻意訓練;3. 嵌入式系統開發過程中的一些小技巧;4. 一個用于智能家居項目
    發表于 11-08 08:23

    系統架構設計的詳細講解

    上一篇,我們討論了故障度量和安全機制的ASIL等級。本篇我們來聊一聊系統架構設計相關內容。01系統架構設計和TSC當我們開始寫TSC時,會涉及到下圖中一系列的內容:當我們完成前三期(鏈接見文末)提到的安全機制規范后,我們就要開始整理好所有的安全需求并在系統
    的頭像 發表于 12-24 14:33 ?1746次閱讀

    SWE.2的軟件架構設

    過程ID:SWE.2 過程名稱:軟件架構設計 過程目的:軟件架構設計過程目的是建立一個架構設計,識別哪些軟件需求應該分配給軟件的哪些要素,并根據已定義的標準評估軟件架構設計。 ? 過程
    的頭像 發表于 01-11 10:36 ?2787次閱讀

    SYS.3的系統架構設

    系統架構設計 過程ID:SYS.3 過程名稱:系統架構設計 ? 過程目的:系統架構設計過程目的,是建立系統架構設計,并確定將哪些系統需求分配給系統的哪些要素,以及根據已定義的準則評估系
    的頭像 發表于 02-13 16:02 ?2715次閱讀

    幾種軟件架構設計的思維方式

    一個優秀的程序員要想成為一名優秀的架構設計師,就改變編程的思維,學會使用架構設計的思維方式。
    的頭像 發表于 03-08 15:30 ?4944次閱讀

    桌面操作系統的架構設計和原理細節

    今天就結合深度桌面操作系統給大家講講桌面操作系統的架構設計和原理細節,一來向外界講講深度這么多年都做了哪些工作,二來希望通過客觀公正的事實向中國新一代的開源愛好者講述怎么用正確的三觀去貢獻自己的力量
    的頭像 發表于 03-20 11:21 ?5248次閱讀

    嵌入式UI架構設計漫談

    嵌入式UI架構設計漫談
    發表于 11-03 17:36 ?15次下載
    嵌入式UI<b class='flag-5'>架構設</b>計漫談

    架構與微架構設

    下面將從芯片的架構設計、微架構設計、使用設計文檔、設計分區、時鐘域和時鐘組、架構調整與性能改進、處理器微架構設計策略等角度進行說明,并以視頻H.264編碼器設計為例。
    的頭像 發表于 05-08 10:42 ?1217次閱讀
    <b class='flag-5'>架構</b>與微<b class='flag-5'>架構設</b>計

    SWE.2軟件架構設

    過程ID : SWE.2 過程名稱 : 軟件架構設計 過程目的 : 軟件架構設計過程目的是建立一個架構設計,識別哪些軟件需求應該分配給軟件的哪些要素,并根據已定義的標準評估軟件架構設
    的頭像 發表于 08-24 09:43 ?954次閱讀

    如何使用tcmalloc來替換glibc的malloc

    代碼中使用tcmalloc替換malloc 我們如何使用tcmalloc來替換glibc的malloc呢? 在鏈接tcmalloc的時候我們可以使用以下任意一種方式: 1.啟動程序之前,預先加載
    的頭像 發表于 11-11 16:52 ?2257次閱讀
    如何使用<b class='flag-5'>tcmalloc</b>來替換glibc的malloc

    交換芯片架構設

    交換芯片的架構設計是網絡設備性能和功能的關鍵。一個高效的交換芯片架構能夠處理大量的數據流量,支持高速數據傳輸,并提供先進的網絡功能。
    的頭像 發表于 03-21 16:28 ?568次閱讀
    主站蜘蛛池模板: 亚洲 自拍 欧洲 视频二区| 伊人情人网综合| 中文字幕 亚洲 有码 在线| 国产亚洲999精品AA片在线爽| 女人高潮被爽到呻吟在线观看| 伊人国产在线观看| 久久视频这里只精品99热在线| 永久免费无码AV国产网站| 快乐激情网| CHINA篮球体育飞机2023| 强伦姧久久久久久久久久| 国产午夜小视频| 91久久精一区二区三区大全| 久久视频这里只精品99re8久| 国产交换丝雨巅峰| 国产视频精品免费| 麻豆久久婷婷五月国产| 一区二区三区高清视频| 69精品国产人妻蜜桃国产毛片| 久久99re热在线观看视频| 在线免费中文字幕| 含羞草完整视频在线播放免费| 校园纯肉H教室第一次| 精品无码久久久久久国产百度| 伊人影院香蕉久在线26| 蜜芽一区二区国产精品| 大胆国模一区二区三区伊人| 学生小泬无遮挡女HD| 久久精品国产欧美日韩99热| 99re6热这里在线精品视频| 日日噜噜夜夜狠狠扒开双腿| 国产精品一区第二页| 一攻多受h嗯啊巨肉bl巨污| 男人网站在线观看| 国产精品A久久久久久久久| 中文有码中文字幕免费视频| 日韩欧美视频一区| 精品麻豆一卡2卡三卡4卡乱码 | 欧洲人交xxx69| 久久草香蕉频线观| 国产精亚洲视频综合区|