Go 内存管理与分配
ddatsh
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