###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,三种类型的处理方式有所不同。
1_TinySize = 16 2_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的内存块。
1// sizeclass 2// class bytes/obj bytes/span objects waste bytes 3// 1 8 8192 1024 0 4// 2 16 8192 512 0 5// 3 32 8192 256 0 6// 4 48 8192 170 32 7// 5 64 8192 128 0 8// 6 80 8192 102 32 9// 7 96 8192 85 32 10// 8 112 8192 73 16 11// 9 128 8192 64 0 12// 10 144 8192 56 128 13// 11 160 8192 51 32 14// 12 176 8192 46 96 15// 13 192 8192 42 128 16// 14 208 8192 39 80 17// 15 224 8192 36 128 18// 16 240 8192 34 32 19// 17 256 8192 32 0 20// 18 288 8192 28 128 21// 19 320 8192 25 192 22// 20 352 8192 23 96 23// 21 384 8192 21 128 24// 22 416 8192 19 288 25// 23 448 8192 18 128 26// 24 480 8192 17 32 27// 25 512 8192 16 0 28// 26 576 8192 14 128 29// 27 640 8192 12 512 30// 28 704 8192 11 448 31// 29 768 8192 10 512 32// 30 896 8192 9 128 33// 31 1024 8192 8 0 34// 32 1152 8192 7 128 35// 33 1280 8192 6 512 36// 34 1408 16384 11 896 37// 35 1536 8192 5 512 38// 36 1792 16384 9 256 39// 37 2048 8192 4 0 40// 38 2304 16384 7 256 41// 39 2688 8192 3 128 42// 40 3072 24576 8 0 43// 41 3200 16384 5 384 44// 42 3456 24576 7 384 45// 43 4096 8192 2 0 46// 44 4864 24576 5 256 47// 45 5376 16384 3 256 48// 46 6144 24576 4 0 49// 47 6528 32768 5 128 50// 48 6784 40960 6 256 51// 49 6912 49152 7 768 52// 50 8192 8192 1 0 53// 51 9472 57344 6 512 54// 52 9728 49152 5 512 55// 53 10240 40960 4 0 56// 54 10880 32768 3 128 57// 55 12288 24576 2 0 58// 56 13568 40960 3 256 59// 57 14336 57344 4 0 60// 58 16384 16384 1 0 61// 59 18432 73728 4 0 62// 60 19072 57344 3 128 63// 61 20480 40960 2 0 64// 62 21760 65536 3 256 65// 63 24576 24576 1 0 66// 64 27264 81920 3 128 67// 65 28672 57344 2 0 68// 66 32768 32768 1 0
参考文献: