源码基于go1.8rc3。

首先看看mheap的数据结构

// mheap本身只包含"free[]" and "large"数组
// 但其他的全局数据也在这里
// mheap 禁止从堆上创建,因包含的mSpanLists不能从堆上创建
type mheap struct {
	lock      mutex
	free      [_MaxMHeapList]mSpanList // free lists of given length
	freelarge mSpanList                // free lists length >= _MaxMHeapList
	busy      [_MaxMHeapList]mSpanList // busy lists of large objects of given length
	busylarge mSpanList                // busy lists of large objects length >= _MaxMHeapList
	sweepgen  uint32                   // sweep generation, see comment in mspan
	sweepdone uint32                   // all spans are swept

    // allspans是所有曾经创建过的mspans的数组,每个mspan只存储一次
    // allspans的内存是手动管理的,随着堆的增长,可以重新创建或移动
    // 一般来说,allspans是被mheap.lock所保护,当释放backing store时,锁用于防止并发的访问
    // 在STW期间访问可能不会持有锁,但必须确保分配不会发生在访问的时候(因为这可能释放backing store)
	allspans []*mspan // all spans out there


    // spans是一张查询表,用于映射虚拟地址页的id到*mspan
    // 对于已经分配spans,它们的页映射到span本身
    // 对于空闲的spans,只有最低位和最高位的页映射到span本身
    // 内部的页映射到一个固定的span
    // 对于从未分配过的页,span是空的
    // 空间分配在一个预先储备好大块的地址上,因此它可以不断增长而不需要移动。len(spans)是分配出去的内存,
    // cap(spans)是所有储备的内存空间
	spans []*mspan

    // sweepSpans包含两个mspan栈,一个是已经清理的使用中的spans,一个是未清理的使用中的spans。
    // 这两个角色在每个GC周期相互转换,因此sweepgen这个字段在每个GC周期中增加2,这意味着清理完的spans
    // 存放在sweepSpans[sweepgen/2%2],而未清理的spans存放在sweepSpans[1-sweepgen/2%2]。
    // 清理过程会把spans从未清理的栈中取出来,并把使用中的spans放到清理完成的栈中。同样的,分配一个使用中      
    // 的span会把它放到已清理的栈中
	sweepSpans [2]gcSweepBuf

	_ uint32 // align uint64 fields on 32-bit for atomics

	// Proportional sweep
	pagesInUse        uint64  // pages of spans in stats _MSpanInUse; R/W with mheap.lock
	spanBytesAlloc    uint64  // bytes of spans allocated this cycle; updated atomically
	pagesSwept        uint64  // pages swept this cycle; updated atomically
	sweepPagesPerByte float64 // proportional sweep ratio; written with lock, read without
	// TODO(austin): pagesInUse should be a uintptr, but the 386
	// compiler can't 8-byte align fields.

	// Malloc stats.
	largefree  uint64                  // bytes freed for large objects (>maxsmallsize)
	nlargefree uint64                  // number of frees for large objects (>maxsmallsize)
	nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)

	// range of addresses we might see in the heap
	bitmap         uintptr // Points to one byte past the end of the bitmap
	bitmap_mapped  uintptr
	arena_start    uintptr
	arena_used     uintptr // always mHeap_Map{Bits,Spans} before updating
	arena_end      uintptr
	arena_reserved bool

	// central free lists for small size classes.
	// the padding makes sure that the MCentrals are
	// spaced CacheLineSize bytes apart, so that each MCentral.lock
	// gets its own cache line.
	central [_NumSizeClasses]struct {
		mcentral mcentral
		pad      [sys.CacheLineSize]byte
	}

	spanalloc             fixalloc // allocator for span*
	cachealloc            fixalloc // allocator for mcache*
	specialfinalizeralloc fixalloc // allocator for specialfinalizer*
	specialprofilealloc   fixalloc // allocator for specialprofile*
	speciallock           mutex    // lock for special record allocators.
}

原文:大专栏  golang内存分配 (二)


02-01 05:40