# runtime off-heap object allocator
runtime 中有很多内部的数据结构是与内存分配、垃圾回收相关的,这些数据结构的实例占用的内存空间会直接通过sysAlloc分配,或则是基于sysAlloc再封装一层或多层的分配器。

上图列举了runtime中内部的一些数据结构所使用的分配器,总共有 3 个,分别是sysAlloc、persistent allocator 、fix allocator。 persistent allocator 管理的空间,从sysAlloc分配得到,而fix allocator管理的空间,从persistent allocator 分配
# Persistent allocator
persistent allocator 就是一个 sequential allocator,不过因为其分配出去的空间都不释放,所以叫做persistent allocator 。
persistent allocator 的数据结构非常简单,其维护了两个变量,一个是base,表示被管理的空间的起始地址,off (offset) 用于记录可用空间的起始地址与 base 的距离。persistent allocator 管理的空间(persistent chunk size)大小是 256 KB,当剩余空间不足以分配的时候,会调用sysAlloc 再申请一个 persistent chunk 。如果请求分配的大小大于64KB,会直接走sysAlloc
type persistentAlloc struct{
base *notInHeap //notInHeap 是 指针类型
off uintptr
}
2
3
4

persistent allocator 会有一些空间浪费,包括对齐的浪费和尾部的浪费,如上图所示。每个P都有一个persistent allocator,因此分配不会出现竞争,所有 (指每个P)persistent chunk都会串在一起,每个新分配的persistent chunk 的起始部分会保留前一个persistent chunk 的首地址,而这个新创建的chunk 的首地址会存在一个全局变量 persistentChunks 中,通过原子操作进行更改。
把每个chunk 串起来的目的不是为了利用尾部的空闲空间,而是为了用与判断某个地址是否落在persistent chunk 中(垃圾回收的某一阶段需要判断指针写入的地址是否合法(写到非go管理的内存范围内),指向persistent chunk地址范围内的指针也是合法的一种)
# fixed size allocator
fixed-size allocator 用于分配runtime中常用的对象,比如内存管理相关的mspan。fixed-size allocator的设计与free-list allocator 类似,不过list 上的对象都是固定大小的。
type fixalloc struct {
size uintptr
first func(arg, p unsafe.Pointer)
arg unsafe.Pointer
list *mlink
chunk uintptr
nchunk uint32
inuse uintptr
stat *uint64
zero bool
}
type mlink struct {
next *mlink
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 字段 | 用途 |
|---|---|
| size | 分配器分配的对象的大小 |
| first | 一个函数,当分配器分配一个对象的时候,就会传入对象首地址,调用这个函数。唯一一个使用场景是当mspan对象被分配的时候,该函数把这个新分配的mspan加到全局的数组中 |
| arg | first 函数的第一个参数 |
| list | free list 的链表头 |
| chunk | 下一个空闲块的首地址 |
| nchunk | 剩余空闲地址块的大小 |
| inuse | 被使用的空间大小 |
| stat | 统计相关 |
| zero | 表示分配出去的空间是否需要清0 |

上图展示了fixed-size allocator 的工作原理,fixed-size allocator 的底层分配器是 persistent allocator ,fixed-size allocator 通过persistent allocator 分配16KB 大小的 chunk用于分配,当空间回收时,就把空闲的空间块挂在free list 中(指针存在空闲块中)。分配的时候,优先从free list 中分配,如果free list 为空,则从chunk处取出size大小的空闲块用于分配。如果free list 没有可用空间,nchunk也不满足分配需求,fixed-size allocator会再申请16KB空间,用于分配。