Go内存示意图
page
内存页面的最小单元,大小为:_PageShift = 13;_PageSize = 1 << _PageShift = 8KB
mheap
是一个全局唯一的对象,代表整个堆,当堆空间不够时,会通过 mmap 系统调用申请一块大小为 64MB 的内存,封装为一个 arena 进行管理。
mheap 中 arenas 数组最多可以管理:4194304 个 arena,每个 arena 64MB,所以 mheap 总共可以管理 256TB 的内存。
type mheap struct {
allspans []*mspan // all spans out there
arenas [1]*[4194304]*heapArena
central [134]struct { // 134 = 57 * 2,有 57 种大小类型的内存
mcentral mcentral
}
}
arena
每个 arena 64 MB
// pagesPerArena = 8192 = 8 * 1024
// heapArenaBitmapBytes = 2097152 = 2 * 1024 * 1024
type heapArena struct {
// bitmap stores the pointer/scalar bitmap for the words in
// this arena. See mbitmap.go for a description. Use the
// heapBits type to access this.
bitmap [heapArenaBitmapBytes]byte
spans [pagesPerArena]*mspan // 页到 mspan 的映射
pageInUse [pagesPerArena / 8]uint8 // bitmap 标记哪些页在使用中
}
mspan
Go 内存分配的最基本单元,从 8KB 到 32KB 分为 67 个不同的类别
type mspan struct {
next *mspan // 用于在 mheap 上构建 mspan 链表
prev *mspan // 用于在 mheap 上构建 mspan 链表
startAddr uintptr // 内存开始地址
npages uintptr // page 的数量
}
mcentral
相同大小的 mspan 会归类到一个 mcentral 中,内存不够时从 mheap 申请
type mcentral struct {
nonempty mSpanList // 使用中
empty mSpanList // 空闲列表
}
mcache
P 私有的小对象内存管理者,从 mcentral 申请新内存。
小对象(< 32KB)会在 mcache 上申请,不用加锁,大对象则在 mheap 上直接分配。
type mcache struct {
alloc [numSpanClasses134]*mspan
}