Go内存示意图

img{512x368}

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
}