【Golang】內(nèi)存管理

概述

全局內(nèi)存

Golang的內(nèi)存管理與C語言的有所區(qū)別:C語言使用Malloc進(jìn)行內(nèi)存分配,使用的是gclib提供的ptmalloc2方法;Golang的內(nèi)存分配方法類似于Google的TCMalloc,以及MC的內(nèi)存池管理方式,即:

  • 預(yù)先申請一大塊全局內(nèi)存,即Arena 堆,大小為512G
  • 每個線程需要使用內(nèi)存時向全局內(nèi)存申請,并維護(hù)在線程內(nèi)部的結(jié)構(gòu)中作為私有內(nèi)存

該方法相對于ptmalloc更好地支持了多線程場景,并且優(yōu)化了外碎片(類似于操作系統(tǒng)的頁式管理)

內(nèi)存塊管理

  • 全局內(nèi)存Arena 內(nèi)部切分為Page,每個Page大小為8KB;
  • 分配內(nèi)存時按照塊(Span)為單位,共有67種大小,最小為8Bytes,最大為32KB;大的Span需要由多頁組成,并且可能會產(chǎn)生一定的內(nèi)碎片:
    • 大塊span大小為8KB,那么需要1頁,湊出1個這樣的Span,無碎片;
    • 小塊span大小為480Bytes,一頁可以分配17個這樣的Span,剩余32KB為內(nèi)碎片;

目前67種SpanClass詳情如下:

  • bytes/obj:塊大小
  • bytes/span:實際占用的內(nèi)存大?。╬age為單位)
  • objects:目前內(nèi)存占用可以得到的塊數(shù)
  • tail_waste:內(nèi)碎片大小
// class  bytes/obj  bytes/span  objects  tail waste  max waste
//     1          8        8192     1024           0     87.50%
//     2         16        8192      512           0     43.75%
//     3         32        8192      256           0     46.88%
//     4         48        8192      170          32     31.52%
//     5         64        8192      128           0     23.44%
//     6         80        8192      102          32     19.07%
//     7         96        8192       85          32     15.95%
//     8        112        8192       73          16     13.56%
//     9        128        8192       64           0     11.72%
//    10        144        8192       56         128     11.82%
//    11        160        8192       51          32      9.73%
//    12        176        8192       46          96      9.59%
//    13        192        8192       42         128      9.25%
//    14        208        8192       39          80      8.12%
//    15        224        8192       36         128      8.15%
//    16        240        8192       34          32      6.62%
//    17        256        8192       32           0      5.86%
//    18        288        8192       28         128     12.16%
//    19        320        8192       25         192     11.80%
//    20        352        8192       23          96      9.88%
//    21        384        8192       21         128      9.51%
//    22        416        8192       19         288     10.71%
//    23        448        8192       18         128      8.37%
//    24        480        8192       17          32      6.82%
//    25        512        8192       16           0      6.05%
//    26        576        8192       14         128     12.33%
//    27        640        8192       12         512     15.48%
//    28        704        8192       11         448     13.93%
//    29        768        8192       10         512     13.94%
//    30        896        8192        9         128     15.52%
//    31       1024        8192        8           0     12.40%
//    32       1152        8192        7         128     12.41%
//    33       1280        8192        6         512     15.55%
//    34       1408       16384       11         896     14.00%
//    35       1536        8192        5         512     14.00%
//    36       1792       16384        9         256     15.57%
//    37       2048        8192        4           0     12.45%
//    38       2304       16384        7         256     12.46%
//    39       2688        8192        3         128     15.59%
//    40       3072       24576        8           0     12.47%
//    41       3200       16384        5         384      6.22%
//    42       3456       24576        7         384      8.83%
//    43       4096        8192        2           0     15.60%
//    44       4864       24576        5         256     16.65%
//    45       5376       16384        3         256     10.92%
//    46       6144       24576        4           0     12.48%
//    47       6528       32768        5         128      6.23%
//    48       6784       40960        6         256      4.36%
//    49       6912       49152        7         768      3.37%
//    50       8192        8192        1           0     15.61%
//    51       9472       57344        6         512     14.28%
//    52       9728       49152        5         512      3.64%
//    53      10240       40960        4           0      4.99%
//    54      10880       32768        3         128      6.24%
//    55      12288       24576        2           0     11.45%
//    56      13568       40960        3         256      9.99%
//    57      14336       57344        4           0      5.35%
//    58      16384       16384        1           0     12.49%
//    59      18432       73728        4           0     11.11%
//    60      19072       57344        3         128      3.57%
//    61      20480       40960        2           0      6.87%
//    62      21760       65536        3         256      6.25%
//    63      24576       24576        1           0     11.45%
//    64      27264       81920        3         128     10.00%
//    65      28672       57344        2           0      4.91%
//    66      32768       32768        1           0     12.50%

數(shù)據(jù)結(jié)構(gòu)

內(nèi)存管理-數(shù)據(jù)結(jié)構(gòu)

如圖,Golang內(nèi)存管理分為全局內(nèi)存管理和線程內(nèi)存管理;線程內(nèi)存不足時向全局內(nèi)存申請,并且緩存在線程內(nèi)部作為私有內(nèi)存;

  1. 全局內(nèi)存管理:MHeap
  • 【67*2】MCentral,因為MCentral是以SpanClass進(jìn)行區(qū)分的,一共67種SpanClass,這里為每種Class配備兩組,一組用于值存儲,一組用于指針存儲;
  • MCentral結(jié)構(gòu)中包含Non-Empty(可分配)和Empty(未分配)的兩個雙向鏈表,每個節(jié)點為MSpan,即當(dāng)前SpanClass下所有可分配的Span集合;
    注意:MCentral結(jié)構(gòu)初始化時,是空的,所有內(nèi)存都需要向MHeap中進(jìn)行申請。
  1. 線程內(nèi)存管理:MCache By P
  • 【67*2】MSpan,線程內(nèi)的內(nèi)存管理也是按照SpanClass進(jìn)行存儲的,對應(yīng)指針/值,值的部分在GC掃描時無需掃描
  • MSpan結(jié)構(gòu)中包含:含有多少個塊(小塊),使用了多少個Page(大塊),AllocBits(Bitmap,用于存儲塊的分配情況),以及當(dāng)前的SpanClass - 對應(yīng)塊的Size
    注意:Mspan有前后指針,在Mcache和MCentral中均為雙向鏈表結(jié)構(gòu),用于存儲多個Mspan結(jié)構(gòu)

內(nèi)存申請流程

1.計算合適的塊大?。鹤罱咏臑閏lass=44,size=4864的塊
2.查詢當(dāng)前P對應(yīng)的MCache結(jié)構(gòu)體中對應(yīng)class=44的MSpan結(jié)構(gòu)體中是否仍有未分配完的塊:如仍有,則直接分配,在Mcache[44].AllocBits中記下分配的塊

  1. 如MCache[44]中的塊都已分配完,或者M(jìn)Cache[44]尚未初始化,則線程向MCentral申請內(nèi)存
  • MHeap.centrals[44]中l(wèi)ock加鎖
  • 查看MHeap.centrals[44]中的non-empty雙向鏈表中是否有Span,如有則直接分配,返回給進(jìn)程
  • MHeap.centrals[44]中l(wèi)ock解鎖
  • MCache[44]中緩存被分配的Span
  1. 如MHeap.centrals[44]中無空余Span或者M(jìn)heap.Centrals[44]尚未初始化,則MCentral向MHeap申請內(nèi)存
  • Mheap.Lock加鎖
  • MHeap從Arena中分配一塊兒內(nèi)存,arena_used向后移動
  • MHeap.centrals[44]中加入對應(yīng)的Span
  • Mheap.lock解鎖

參考

  1. 圖解Golang的內(nèi)存分配
  2. Golang內(nèi)存池
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容