Golang 内存管理

58 阅读2分钟
  • page:页是操作系统中用来描述内存大小的一个单位名称,一个页的含义是大小为4K(1024*4=4096字节)
  • span:多个先连续的page组成的一片区域

接下来看看几个重要的数据结构。


// 存储单元
type mspan struct {
    _    sys.NotInHeap
    // 这里标识前后节点的指针
    next *mspan     // next span in list, or nil if none
    prev *mspan     // previous span in list, or nil if none
    
    // span 起始的地址
    startAddr uintptr // address of first byte of span aka s.base()
    // 占用的页数
    npages    uintptr // number of pages in span

    
    // 标识此前前的位置已经被占用
    freeindex uintptr
    // TODO: Look up nelems from sizeclass and remove this field if it
    // helps performance.
    
    // 最多可以存放多少个object
    nelems uintptr // number of object in the span.
  
    // bitmap 每个bit对应的object快,标识该块是否被占用
    allocCache uint64


    // span的等级
    spanclass             spanClass     // size class and noscan (uint8)
    ...
}

// 线程缓存
type mcache struct {
    _ sys.NotInHeap

    nextSample uintptr // trigger heap sample after allocating this many bytes
    scanAlloc  uintptr // bytes of scannable heap allocated
    
    // 为对象分配内存相关
    tiny       uintptr  
    tinyoffset uintptr
    tinyAllocs uintptr

    // The rest is not accessed on every malloc.

    // numSpanClasses = 136
    // numSpanClasses = 136 = 67(size classes)× 2(scan/noscan) + 保留 class
    // 
    alloc [numSpanClasses]*mspan // spans to allocate from, indexed by spanClass

    stackcache [_NumStackOrders]stackfreelist

    // 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 atomic.Uint32
    ...
}

// 中心缓存
type mcentral struct {
    _         sys.NotInHeap
    // 对应一种spanClass
    spanclass spanClass
    // 可以再继续分配的mspan的集合
    partial [2]spanSet // list of spans with a free object
    // 暂时满了的集合 等带GC回收之后回归可用
    full    [2]spanSet // list of spans with no free objects
}

// 堆缓存
type mheap struct {
    lock      mutex       // 全局锁,保护大部分字段
    pages     pageAlloc   // 页分配器,负责分配大块的页
    sweepgen  uint32      // 垃圾回收相关的代数标记
    sweepdone uint32      // 所有 span 是否都已清扫

    spans     []*mspan    // spans 数组,用于记录每一页属于哪个 span
    arenas    []*heapArena // 指向 arena 的切片,每个 arena 管理 64MB 的空间
    allspans  []*mspan     // 所有的 span(用于 sweep)
    
    central   [numSpanClasses]mcentral // 所有 spanClass 对应的 mcentral
    busy      uint64      // 用于调试 & 统计

    ...
}