mspan简介
Go中内存管理的基本单元,是由一片连续的 8KB的页组成的大块内存。注意,这里的页和操作系统本身的页并不是一回事,它一般是操作系统页大小的几倍。一句话概括: mspan是一个包含起始地址、 mspan规格、页的数量等内容的双端链表。
关于span的状态:
关于mspan的状态转换:
当mspan在堆的空闲treap(详情见备注)上,它的状态为mSpanFree
当mspan在清除treap上,当且仅当此时,scavengedtrue,其他所有情况该变量为false
当mspan是被使用的,它的状态为mSpanInUse,或者mSpanManual
1.span将从free到in-use或者manual在GC的任何阶段
2.在清除阶段gcphase_GCoff,span可以从in-use或者manual到free,in-use的转变对应的是清除,manual的转变对应的是堆栈被释放。
3.在整个gc,gcphase!=_GCoff,span不可以从manual或者in-use到free。因为当前GC读取指针并遍历它的span,span的状态必须保持单调。
mspan的图
mspan中allbits记录着哪些元素是已分配的,哪些未分配。alloccache用数字按位代表freeindex开始的
源码分析
1.mspanlist
//表示span的列表
//go:notinheap
type mSpanList struct {
first *mspan // first span in list, or nil if none
last *mspan // last span in list, or nil if none
}
2.mspan
type mspan struct {
//指向下一个span的指针
next *mspan
//指向上一个span的指针
prev *mspan
list *mSpanList
//span第一个字节的地址
startAddr uintptr
//当前mspan的页数
npages uintptr // number of pages in span
//在mSpanManual的空闲对象
manualFreeList gclinkptr
//freeindex标记0~belems之间的插槽索引,标记的的是在span中的下一个空闲对象
//每次分配内存都从freeindex开始,直到遇到表示空闲对象的地方,之后调整freeindex使得下一次扫描能跳过上一次的分配
//若freeindex==nelem,则当前span没有了空余对象
//
//allocBits是这个span的位图
freeindex uintptr
// TODO: Look up nelems from sizeclass and remove this field if it
// helps performance.
nelems uintptr // number of object in the span.
//在freeindex处的allocBits的缓存.
//allocCache的最低位对应于freeindex位。
//allocCache保留allocBits的补码,从而允许ctz(计数尾随零)直接使用它。
//allocCache可能包含s.nelems以外的位; 呼叫者必须忽略这些。
//作用是记录未被使用的地址
allocCache uint64
//allocBits标记span中的elem哪些是被使用的,哪些是未被使用的
//gc,arkBits标记span中的elem哪些是被标记了的,哪些是未被标记的
allocBits *gcBits
gcmarkBits *gcBits
// sweep generation:
// if sweepgen == h->sweepgen - 2, the span needs sweeping
// if sweepgen == h->sweepgen - 1, the span is currently being swept
// if sweepgen == h->sweepgen, the span is swept and ready to use
// if sweepgen == h->sweepgen + 1, the span was cached before sweep began and is still cached, and needs sweeping
// if sweepgen == h->sweepgen + 3, the span was swept and then cached and is still cached
// h->sweepgen is incremented by 2 after every GC
sweepgen uint32
divMul uint16 // for divide by elemsize - divMagic.mul
baseMask uint16 // if non-0, elemsize is a power of 2, & this will get object allocation base
allocCount uint16 // number of allocated objects
spanclass spanClass // size class and noscan (uint8)
state mSpanState // mspaninuse etc
needzero uint8 // needs to be zeroed before allocation
divShift uint8 // for divide by elemsize - divMagic.shift
divShift2 uint8 // for divide by elemsize - divMagic.shift2
scavenged bool // whether this span has had its pages released to the OS
elemsize uintptr // computed from sizeclass or from npages
unusedsince int64 // first time spotted by gc in mspanfree state
limit uintptr // end of data in span
speciallock mutex // guards specials list
specials *special // linked list of special records sorted by offset.
}
备注:
treap:是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。
mcache简介:
Gorontine 的运行都是绑定到一个 P 上面,mcache 是每个 P 的 cache。
好处是不需要加锁就可以完成内存的分配。
源码分析
type mcache struct {
// The following members are accessed on every mallc,
// so they are grouped here for better caching.
next_sample int32 // trigger heap sample after allocating this many bytes
local_scan uintptr // bytes of scannable heap allocated
// Allocator cache for tiny objects w/o pointers.
// See "Tiny allocator" comment in malloc.go.
// tiny points to the beginning of the current tiny block, or
// nil if there is no current tiny block.
//
// tiny is a heap pointer. Since mcache is in non-GC'd memory,
// we handle it by clearing it in releaseAll during mark
// termination.
tiny uintptr
tinyoffset uintptr
local_tinyallocs uintptr // number of tiny allocs not counted in other stats
// The rest is not accessed on every malloc.
//alloc是span数组,长度是67 << 1,说明每种size class有2组元素。第一组span对象中包含了指针,叫做scan,表示需要gc scan;第二组没有指针,叫做noscan。提高gc scan性能。
alloc [numSpanClasses]*mspan // spans to allocate from, indexed by spanClass
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
}
参考:
https://www.jianshu.com/p/2a899f940f68