go内存
一、分配内存的两个方法
1.make:返回Type
2.new:返回*Type
一、go内存介绍
内存分配算法TCMalloc(Thread-Caching Malloc),看第2节
二、内存管理流程
1.arena,bitmap,spans
程序启动的时候,会先向操作系统申请一块虚拟内存,然后切成小块后自己进行管理。申请到的内存块被分配了三个区域,在X64上分别是512MB(spans),16GB(bitmap),512GB(arena)大小
arena
堆区,用来动态分配内存,把内存分割成8KB大小的页,一些页组合起来称为mspan。
bitmap
标识arena区域哪些地址保存了对象,并且用4bit标志位表示对象是否包含指针、GC标记信息。
bitmap中一个byte大小的内存对应arena区域中4个指针大小(指针大小为 8B )的内存
spans
存放mspan的指针,也就是一些arena分割的页组合起来的内存管理基本单元,
每个指针对应一页,创建mspan的时候,按页填充对应的spans区域,在回收对象时,
根据地址很容易就能找到它所属的mspan
2.内存管理单元
mspan是Go中内存管理的基本单元,是由一片连续的8KB的页组成的大块内存,mspan是一个包含起始地址、mspan规格、页的数量等内容的双端链表
mspan源代码路径:goroot下的 \src\runtime\mheap.go:335
type mspan struct {
//链表前向指针,用于将spans链接起来
next *mspan
//链表前向指针,用于将spans链接起来
prev *mspan
// 起始地址,也即所管理页的地址
startAddr uintptr
// 管理的页数
npages uintptr
// 块个数,表示有多少个块可供分配
nelems uintptr
//分配位图,每一位代表一个块是否已分配
allocBits *gcBits
// 已分配块的个数
allocCount uint16
// class表中的class ID,和Size Classs相关
spanclass spanClass
// class表中的对象大小,也即块大小
elemsize uintptr
}
type span struct {
start int
end int
}
3.内存管理组件
- mcache
mcache在初始化时没有任何mspan资源,在使用过程中会动态地从mcentral申请
goroot下的 \src\runtime\mcache.go:19
type mcache struct {
next_sample uintptr // trigger heap sample after allocating this many bytes
local_scan uintptr // bytes of scannable heap allocated
tiny uintptr
tinyoffset uintptr
local_tinyallocs uintptr // number of tiny allocs not counted in other stats
alloc [numSpanClasses]*mspan
stackcache [_NumStackOrders]stackfreelist
// Local allocator stats, flushed during GC.
local_largefree uintptr // bytes freed for large objects (>maxsmallsize)
local_nlargefree uintptr // number of frees for large objects (>maxsmallsize)
local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize)
// flushGen indicates the sweepgen during which this mcache
// was last flushed. If flushGen != mheap_.sweepgen, the spans
// in this mcache are stale and need to the flushed so they
// can be swept. This is done in acquirep.
flushGen uint32
}
- mcentral
为所有mcache提供切分好的mspan资源,每个mcentral对应一种sizeClass的mspan
goroot下的 \src\runtime\mcentral.go:20
type mcentral struct {
// 互斥锁
lock mutex
// 规格
sizeclass int32
// 尚有空闲object的mspan链表
nonempty mSpanList
// 没有空闲object的mspan链表,或者是已被mcache取走的msapn链表
empty mSpanList
// 已累计分配的对象个数
nmalloc uint64
}
- mheap
堆空间。当mcentral没有空闲的mspan时,会向mheap
goroot下的 \src\runtime\mheap.go:31
type mheap struct {
lock mutex
// spans: 指向mspans区域,用于映射mspan和page的关系
spans []*mspan
// 指向bitmap首地址,bitmap是从高地址向低地址增长的
bitmap uintptr
// 指示arena区首地址
arena_start uintptr
// 指示arena区已使用地址位置
arena_used uintptr
// 指示arena区末地址
arena_end uintptr
central [67*2]struct {
mcentral mcentral
pad [sys.CacheLineSize - unsafe.Sizeof(mcentral{})%sys.CacheLineSize]byte
}
...
}
分配流程:
对象<=16B 的对象使用mcache的tiny分配器分配;
16B<对象<=32KB ,首先计算对象的规格大小(sizeClass,共有76种),然后使用mcache中相应规格大小的mspan分配;
对象>32KB ,直接从mheap上分配;
mcache–>mcentral–>mheap
如果mcache没有相应规格大小的mspan,则向mcentral申请
如果mcentral没有相应规格大小的mspan,则向mheap申请
如果mheap中也没有合适大小的mspan,则向操作系统申请
注:
sizeClass:比如某mspan的sizeClass为3,那么其划分的object大小就是32B,可以存储(16B,32B]大小的的对象