Go 语言内存管理详解 | 青训营笔记

83 阅读2分钟

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

内存管理分配

Go语言内存分配全局视野

span与元素

当对象需要分配内存时,不是直接分配span而是分配span中的元素

每个具体的对象在分配时需要对齐到指定的大小,例如17字节的对象会被分配到最接近它的元素级别32字节

三级对象管理

  • mcache:每个逻辑处理器P都存储了一个本地span缓存。协程需要内存直接从mcache中获取。mcache包含所有大小规格的mspan,但是每种规格大小只包含一个。除了class0外,mcache的span都来自mcentral

  • mcentral:mcentral被所有逻辑处理器共享。mcentral收集所有给定规格大小的span。每个mcentral包含两个mspan的链表:empty mspanList表示没有空闲对象的span或span已经被mcache缓存的链表,nonemptymspanList表示有空闲对象的span链表

  • mheap:管理mcentral,大对象也会直接通过mheap进行分配

四级内存块管理

73a5c1e75293d5c080a06d4767fe033.jpg

对象分配

微小对象

小于16字节的对象。

微小对象会被放入class为2的span中。首先对微小对象按照2、4、8的规律进行字节对齐。

分配过程:

  1. 如果分配的元素中有空余空间,则增加offset,为下一次做准备(尝试利用分配过的前一个元素的空间,达到节约内存的目的)
  2. 如果分配的元素空间不够,将尝试从mcache中查找span中下一个可用的元素

mcache缓存位图

mspan中拥有allocCache字段,作为一个位图,用于标记span中元素是否被分配

mcentral遍历span

当前span中没有可以使用的元素,这时需要从mcentral加锁查找。此时会遍历两个链表,这里为什么要遍历没有空闲元素的链表呢?应为可能有些span虽然被垃圾回收器标记为空闲,但是还没有来得及清理

mheap缓存查找

如果在mcentral中找不到可用的span,就需要在mheap中查找

type pageCache struct {
    base uintptr
    cache uint64
    scav uint64
}

每个逻辑处理器都维护了一份pageCache

4bf390678919f1e42acca53307498b0.jpg

mheap基数树查找

如果要分配的page过大或者在逻辑处理器的cache中没有找到可用的page

操作系统内存申请

每一次向操作系统中申请的内存大小必须为heapArena的倍数

小对象分配

小对象是指小于32KB的对象

mcache -> mcentral -> mheap -> mheap基数树 -> 操作系统分配

大对象分配

是指大于32KB的对象

直接通过mheap进行分配

总结

这次课不仅讲了内存分配也讲了gc,gc放到下次再写,以上是我在学习过程中结合书本所学