golang内存分配 (二)

Feb 8, 2017

源码基于go1.8rc3。

首先看看mheap的数据结构

// mheap本身只包含"free[]" and "large"数组// 但其他的全局数据也在这里// mheap 禁止从堆上创建，因包含的mSpanLists不能从堆上创建typemheapstruct{lockmutexfree[_MaxMHeapList]mSpanList// free lists of given lengthfreelargemSpanList// free lists length >= _MaxMHeapListbusy[_MaxMHeapList]mSpanList// busy lists of large objects of given lengthbusylargemSpanList// busy lists of large objects length >= _MaxMHeapListsweepgenuint32// sweep generation, see comment in mspansweepdoneuint32// 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 sweeppagesInUseuint64// pages of spans in stats _MSpanInUse; R/W with mheap.lockspanBytesAllocuint64// bytes of spans allocated this cycle; updated atomicallypagesSweptuint64// pages swept this cycle; updated atomicallysweepPagesPerBytefloat64// 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.largefreeuint64// bytes freed for large objects (>maxsmallsize)nlargefreeuint64// 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 heapbitmapuintptr// Points to one byte past the end of the bitmapbitmap_mappeduintptrarena_startuintptrarena_useduintptr// always mHeap_Map{Bits,Spans} before updatingarena_enduintptrarena_reservedbool// 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{mcentralmcentralpad[sys.CacheLineSize]byte}spanallocfixalloc// allocator for span*cacheallocfixalloc// allocator for mcache*specialfinalizerallocfixalloc// allocator for specialfinalizer*specialprofileallocfixalloc// allocator for specialprofile*speciallockmutex// lock for special record allocators.}