Go 内存管理与分配

ddatsh

dev #go

Allocation on the heap

package main

type smallStruct struct {
   a, b int64
   c, d float64
}

func main() {
   smallAllocation()
}

//go:noinline
func smallAllocation() *smallStruct {
   return &smallStruct{}
}

//go: noinline 禁用内联优化

go tool compile "-m" main.go ,运行 escape analysis 确认 Go 所做的分配

main.go:14:9: &smallStruct literal escapes to heap

go tool compile -S main.go,转储程序的汇编代码

        0x0024 00036 (main.go:14)       LEAQ    type."".smallStruct(SB), AX
        0x002b 00043 (main.go:14)       PCDATA  $0, $0
        0x002b 00043 (main.go:14)       MOVQ    AX, (SP)
        0x002f 00047 (main.go:14)       CALL    runtime.newobject(SB)

Small allocation

< 32kb 的分配,尝试从 mcache 本地缓存获取,其中有叫 mspan 的 span 列表,包含可用于分配的内存

每个线程 m 被分配给一个处理器 p,每次最多处理一个 goroutine

分配内存时,当前 goroutine 使用当前 m 的本地缓存来查找 span 列表中第一个可用的空闲对象。使用此本地缓存不需要锁

Span 列表分成 70 个大小的类,8 - 32k 字节,存储不同的对象大小

每种span分成有无指针两种,使 GC不必扫描不包含指针的部分


例中结构大小 32 字节,可放入 32 个字节的span

如果在分配期间span没有空闲slot

Go maintains central lists of spans per size classes, called mcentral, with the spans that contain free objects and the ones that do not

Mcentral 维护一个双链表的 span; 每个 span 都有对前一个 span 和下一个 span 的引用。 空列表中的 span 可能已经包含一些正在使用的内存,GC时清理

program can request a span from the central list if it runs out of slots

如果 central list 中 empty list没有可用的spans ,New spans will now be allocated from the heap and linked to the central list

heap pulls the memory from the OS

heap will allocate a large chunk of memory, called arena

64Mb 用于 64 位体系结构,4Mb 用于大多数其他体系结构

The arena also maps the memory page with the spans

Large allocation

Go does not manage the large allocations with a local cache

allocations, greater than 32kb, are rounded up to the page size and the pages are allocated directly to the heap