Go語言記憶體管理(一)記憶體分配 golang作為一種“高級語言”,也提供了自己的記憶體管理機制。這樣一方面可以簡化編碼的流程,降低因記憶體使用導致出現問題的頻率(C語言使用者尤其是初學者應該深有體會),對程式猿友好。另一方面也可以減少記憶體相關係統調用,提升性能。 先瞭解下記憶體管理大致策略: 申請一塊較大 ...
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 開發的多級記憶體分配器,具有對抗記憶體碎片化,適合高併發場景的特性。據稱,它的記憶體分配速度是 glibc2.3 中實現的 malloc的數倍。
和TCMalloc相同,go的記憶體分配也是基於兩種粒度的記憶體單位:span和object。span是連續的page,按page的數量進行歸類,比如分為2個page的span,4個page的span等。object是span中按預設大小劃分的塊,也是按大小分類。同一個span中,只有一種類型(大小)的object。
go記憶體分配主要有三個管理組件:
- mcache
Per-P(Processer,具體參見go中G,M,P的概念)私有cache,用於實現無鎖的object分配
- mcentral
全局記憶體,為各個cache提供按大小劃分好的span
- mheap
全局記憶體,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
參考文獻: