21

【Golang】内存管理

 3 years ago
source link: https://studygolang.com/articles/30997
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

概述

M3yqQ3M.png!mobile

全局内存

Golang的内存管理与C语言的有所区别:C语言使用Malloc进行内存分配,使用的是gclib提供的ptmalloc2方法;Golang的内存分配方法类似于Google的TCMalloc,以及MC的内存池管理方式,即:

  • 预先申请一大块全局内存,即Arena 堆,大小为512G
  • 每个线程需要使用内存时向全局内存申请,并维护在线程内部的结构中作为私有内存

该方法相对于ptmalloc更好地支持了多线程场景,并且优化了外碎片(类似于操作系统的页式管理)

内存块管理

  • 全局内存Arena 内部切分为Page,每个Page大小为8KB;
  • 分配内存时按照块(Span)为单位,共有67种大小,最小为8Bytes,最大为32KB;大的Span需要由多页组成,并且可能会产生一定的内碎片:
    • 大块span大小为8KB,那么需要1页,凑出1个这样的Span,无碎片;
    • 小块span大小为480Bytes,一页可以分配17个这样的Span,剩余32KB为内碎片;

目前67种SpanClass详情如下:

  • bytes/obj:块大小
  • bytes/span:实际占用的内存大小(page为单位)
  • objects:目前内存占用可以得到的块数
  • tail_waste:内碎片大小
// 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%

数据结构

aYBN736.png!mobile

内存管理-数据结构

如图,Golang内存管理分为全局内存管理和线程内存管理;线程内存不足时向全局内存申请,并且缓存在线程内部作为私有内存;

  1. 全局内存管理:MHeap
  • 【67*2】MCentral,因为MCentral是以SpanClass进行区分的,一共67种SpanClass,这里为每种Class配备两组,一组用于值存储,一组用于指针存储;
  • MCentral结构中包含Non-Empty(可分配)和Empty(未分配)的两个双向链表,每个节点为MSpan,即当前SpanClass下所有可分配的Span集合;
    注意:MCentral结构初始化时,是空的,所有内存都需要向MHeap中进行申请。
  1. 线程内存管理:MCache By P
  • 【67*2】MSpan,线程内的内存管理也是按照SpanClass进行存储的,对应指针/值,值的部分在GC扫描时无需扫描
  • MSpan结构中包含:含有多少个块(小块),使用了多少个Page(大块),AllocBits(Bitmap,用于存储块的分配情况),以及当前的SpanClass - 对应块的Size
    注意:Mspan有前后指针,在Mcache和MCentral中均为双向链表结构,用于存储多个Mspan结构

内存申请流程

1.计算合适的块大小:最接近的为class=44,size=4864的块

2.查询当前P对应的MCache结构体中对应class=44的MSpan结构体中是否仍有未分配完的块:如仍有,则直接分配,在Mcache[44].AllocBits中记下分配的块

  1. 如MCache[44]中的块都已分配完,或者MCache[44]尚未初始化,则线程向MCentral申请内存
  • MHeap.centrals[44]中lock加锁
  • 查看MHeap.centrals[44]中的non-empty双向链表中是否有Span,如有则直接分配,返回给进程
  • MHeap.centrals[44]中lock解锁
  • MCache[44]中缓存被分配的Span
  1. 如MHeap.centrals[44]中无空余Span或者Mheap.Centrals[44]尚未初始化,则MCentral向MHeap申请内存
  • Mheap.Lock加锁
  • MHeap从Arena中分配一块儿内存,arena_used向后移动
  • MHeap.centrals[44]中加入对应的Span
  • Mheap.lock解锁

参考

  1. 图解Golang的内存分配
  2. Golang内存池

有疑问加站长微信联系

iiUfA3j.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK