内存分配|青训营笔记

88 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天

Go内存管理

类似内存池管理,维护一大块全局内存,每个线程(P)维护一小块私有内存,私有内存不足再从全局申请

 

Go申请到的内存被分为三个区域(此时还是虚拟内存,没有实际分配)

 

arena:512GB,我们所说的堆区,分割成8KB的页,实际存储数据,一些页合起来称为mspan

bitmap:16GB,位图形式保存arena区域的保存的对象的信息,2bit表示对象是否有指针、gc标记。即1byte表示arena区域4个指针所指的内存,所以bitmap=512GB/(4*8B)=16GB。bitmap的低地址对应arena的低地址

spans:512MB,存放mspan的指针,每个指针对应1页,所以spans=512GB/8KB*8B=512MB。创建mspan时填充对应的spans区域。 span:Go内存的基本单元,是双端链表,自身有Size Class属性,按照Size Class均分成若干个object(可能会有一点被浪费,一点内存没分到object内),每个object存储一个对象。Size Class决定object大小。Size Class有67种,其分割的object和mspan分的page大小是写死的。过小的对象会合并存在一个object中。超过存储32KB的对象Size Class为0,特别对待,mspan根据对象定,直接由堆内存分配。小对象都由mspan分配。

根据object大小去表中查找SizeClass和mspan页数都是固定的。

其实mspan结构体存储着mspan的信息,由spans的指针指向mspan结构体(“结构体本身的内存是系统分配的”),结构体内信息之一的指针指向实际mspan的开头

mspan分为两种,包含指针对象需要GC进行扫描是否连接其他活跃对象,不需要扫描

 

内存分配由内存分配器完成。分配器由3种组件构成:mcache, mcentral, mheap。

mcache

每个工作线程绑定一个mcache,本地缓存可用的mspan资源,这样就可以直接给Goroutine分配,因为不存在多个Goroutine竞争的情况,所以不会消耗锁资源。

 

Span_Class=Size_Class*2 两类mspan,一个存有指针对象,一个存无指针对象。底层就是Size Class<<1,最右一位拼接标志位标记是否含有指针

 

mcache初始没有mspan资源,向mcentral申请后