標籤:規格 c語言 處理 tiny 基於 又能 初學者 gpo bitmap
Go語言記憶體管理(一)記憶體配置
golang作為一種“進階語言”,也提供了自己的記憶體管理機制。這樣一方面可以簡化編碼的流程,降低因記憶體使用量導致出現問題的頻率(C語言使用者尤其是初學者應該深有體會),對程式猿友好。另一方面也可以減少記憶體相關係統調用,提升效能。
先瞭解下記憶體管理大致策略:
- 申請一塊較大的地址空間(虛擬記憶體),用於記憶體配置及管理(golang:spans+bitmap+arena->512M+16G+512G)
- 當空間不足時,向系統申請一塊較大的記憶體,如100KB或者1MB
- 申請到的記憶體塊按特定的size,被分割成多種小塊記憶體(golang:_NumSizeClasses = 67),並用鏈表管理起來
- 建立對象時,按照對象大小,從空閑鏈表中尋找到最適合的記憶體塊
- 銷毀對象時,將對應的記憶體塊返還空閑鏈表中以複用
- 空閑記憶體達到閾值時,返還作業系統
以下,基於go1.9版本,看下golang記憶體配置實現的基本思路。
Go記憶體管理的實現
go的記憶體管理實現基於TCMalloc(Thread-Caching Malloc)。
TCMalloc是 Google 開發的多級記憶體 Clerk,具有對抗記憶體片段化,適合高並發情境的特性。據稱,它的記憶體配置速度是 glibc2.3 中實現的 malloc的數倍。
和TCMalloc相同,go的記憶體配置也是基於兩種粒度的記憶體單位:span和object。span是連續的page,按page的數量進行歸類,比如分為2個page的span,4個page的span等。object是span中按預設大小劃分的塊,也是按大小分類。同一個span中,只有一種類型(大小)的object。
go記憶體配置主要有三個管理組件:
Per-P(Processer,具體參見go中G,M,P的概念)私人cache,用於實現無鎖的object分配
全域記憶體,為各個cache提供按大小劃分好的span
全域記憶體,page管理,記憶體不足時向系統申請
通過將記憶體配置流程分為三個層級,既能保證Processer層級(mcache)的無鎖分配,又能在mcentral層級實現記憶體全域共用,避免浪費。
go將記憶體申請按大小分為三種類型:tiny,small,large。tiny是小於16個byte的申請,small是小於32KB的申請,大於32KB為large,三種類型的處理方式有所不同。
_TinySize = 16_MaxSmallSize = 32768
我們以一個small對象為例,看一下記憶體申請流程:
- 計算對象大小,按預定義的sizeclass表(見下)從私人的mcache中找到對應規格的mspan。比如大小為112 byte的對象,對應8192 byte大小的mspan。然後通過mspan的空閑bitmap尋找閒置塊,如果空閑塊存在,分配完成。
以上是mcache內的分配操作,不需要加鎖。
- 如果mspan沒有空閑塊,則向mcentral申請對應大小的空閑mspan。比如112 byte的對象,需要向mcentral申請8192 byte大小的空閑mspan。
由於申請擷取全域的mspan,需要在mcentral層級加鎖。
如果mcentral中沒有空閑mspan,則向mheap申請,並劃分object。
如果mheap沒有足夠的空閑page,則向作業系統申請不少於1M的page。
以上就是small對象的記憶體配置流程。
large對象的申請,跳過了mcache和mcentral,直接從mheap中分配。
對於tiny對象的申請,mcache中有專門的記憶體地區“tiny”來進行特殊處理。“tiny”將對象按大小與tinyoffset(“tiny”當前分配地址)對齊,然後分配,並記錄下新的tinyoffset,用於下次分配。如果空間不足,則另外申請16 byte的記憶體塊。
// sizeclass// class bytes/obj bytes/span objects waste bytes// 1 8 8192 1024 0// 2 16 8192 512 0// 3 32 8192 256 0// 4 48 8192 170 32// 5 64 8192 128 0// 6 80 8192 102 32// 7 96 8192 85 32// 8 112 8192 73 16// 9 128 8192 64 0// 10 144 8192 56 128// 11 160 8192 51 32// 12 176 8192 46 96// 13 192 8192 42 128// 14 208 8192 39 80// 15 224 8192 36 128// 16 240 8192 34 32// 17 256 8192 32 0// 18 288 8192 28 128// 19 320 8192 25 192// 20 352 8192 23 96// 21 384 8192 21 128// 22 416 8192 19 288// 23 448 8192 18 128// 24 480 8192 17 32// 25 512 8192 16 0// 26 576 8192 14 128// 27 640 8192 12 512// 28 704 8192 11 448// 29 768 8192 10 512// 30 896 8192 9 128// 31 1024 8192 8 0// 32 1152 8192 7 128// 33 1280 8192 6 512// 34 1408 16384 11 896// 35 1536 8192 5 512// 36 1792 16384 9 256// 37 2048 8192 4 0// 38 2304 16384 7 256// 39 2688 8192 3 128// 40 3072 24576 8 0// 41 3200 16384 5 384// 42 3456 24576 7 384// 43 4096 8192 2 0// 44 4864 24576 5 256// 45 5376 16384 3 256// 46 6144 24576 4 0// 47 6528 32768 5 128// 48 6784 40960 6 256// 49 6912 49152 7 768// 50 8192 8192 1 0// 51 9472 57344 6 512// 52 9728 49152 5 512// 53 10240 40960 4 0// 54 10880 32768 3 128// 55 12288 24576 2 0// 56 13568 40960 3 256// 57 14336 57344 4 0// 58 16384 16384 1 0// 59 18432 73728 4 0// 60 19072 57344 3 128// 61 20480 40960 2 0// 62 21760 65536 3 256// 63 24576 24576 1 0// 64 27264 81920 3 128// 65 28672 57344 2 0// 66 32768 32768 1 0
參考文獻:
TCMalloc
圖解 TCMalloc
Go語言記憶體管理(一)記憶體配置