核心数据结构

Go内存管理模块的核心数据结构比较少:

  • mheap:管理全局的从os申请的虚拟内存空间;
  • mspan:将mheap按照固定大小切分而成的细粒度的内存区块,每个区块映射了虚拟内存中的若干连续页面,页大小由Go内部定义;
  • mcache:与线程相关缓存,该结构的存在是为了减少内存分配时的锁操作,优化内存分配性能。
  • mcentral:集中内存池,线程在本地分配失败后,尝试向mcentral申请,如果mcentral也没有资源,则尝试向mheap分配。

mheap

type mheap struct {
        lock      mutex
        // 空闲mspan链表
        free      [_MaxMHeapList]mspan 
        freelarge mspan                
        busy      [_MaxMHeapList]mspan 
        busylarge mspan                
        allspans  **mspan              
        gcspans   **mspan              
        nspan     uint32
        sweepgen  uint32 
        sweepdone uint32 

        spans        **mspan
        spans_mapped uintptr

        // Proportional sweep
        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

        // Malloc stats.
        largefree  uint64                  
        nlargefree uint64                  
        nsmallfree [_NumSizeClasses]uint64 

        // range of addresses we might see in the heap
        bitmap         uintptr
        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      [_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.
}

mheap内部主要维护多级free以及busy mspan链表。每个级别的mspan链表上的mspan总大小相同(即映射的内存页面数一样)。

除此之外,mheap内部还记录了必须的管理信息,如记录位图位置等。这些我们在后面遇到的时候作一一分析。

mspan

type mspan struct {
        // 每个mspan会根据状态被link到特定的双向链表中(如free、busy链表)
        next     *mspan
        prev     *mspan
        // 该mspan映射的起始内存page以及page数
        start    pageID    
        npages   uintptr   
        freelist gclinkptr 
        // 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
        // h->sweepgen is incremented by 2 after every GC
        sweepgen    uint32
        divMul      uint32   
        ref         uint16   
        sizeclass   uint8    // size class
        incache     bool     // being used by an mcache
        state       uint8    // mspaninuse etc
        needzero    uint8    // needs to be zeroed before allocation
        divShift    uint8    
        divShift2   uint8
        // ???
        elemsize    uintptr  
        unusedsince int64    // first time spotted by gc in mspanfree state
        npreleased  uintptr  // number of pages released to the os
        limit       uintptr  // end of data in span
        speciallock mutex    // guards specials list
        specials    *special // linked list of special records sorted by offset.
        baseMask    uintptr  // if non-0, elemsize is a power of 2, & this will get object allocation base
}

mspan中记录的最关键信息是freelist:所有的对象分配最终都被委派到从mspan上以分配合适大小的内存空间。因此,mspan在经历分配、释放等过程之后,也会变得支离破碎,如下图所示:

mcache

// Per-thread (in Go, per-P) cache for small objects.
// No locking needed because it is per-thread (per-P).
type mcache struct {
        // The following members are accessed on every malloc,
        // so they are grouped here for better caching.
        next_sample      int32   
        local_cachealloc uintptr 
        local_scan       uintptr 
        // Allocator cache for tiny objects w/o pointers.
        // See "Tiny allocator" comment in malloc.go.
        tiny             unsafe.Pointer
        tinyoffset       uintptr
        local_tinyallocs uintptr // number of tiny allocs not counted in other stats

        // The rest is not accessed on every malloc.
        alloc [_NumSizeClasses]*mspan 
        // Local allocator stats, flushed during GC.
        local_nlookup    uintptr                  // number of pointer lookups
        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)
}

mcentral

// Central list of free objects of a given size.
type mcentral struct {
    lock      mutex
    // mcentral负责分配的内存块大小
    sizeclass int32
    // 拥有空闲object的mspan链表
    nonempty  mspan
    // 无空闲object的mspan链表
    empty     mspan 
}

数据结构关系图

  1. mheap管理向os申请、释放、组织span;
  2. mcentral按照自己管理的块大小将span划分成多个小block,并分配给mcache;
  3. mspan是数据的实际存储区域,按照central管理的块规格被切分成小block;
  4. mcache管理不同规格(块大小)的mspan:规格相同的mspan被链接到同一个链表中。

results matching ""

    No results matching ""