Interviewer: Let’s talk about Go memory allocation strategy

Hello everyone, my name is Mu Chuan

The Go language has a built-in runtime (runtime), which abandons the traditional memory allocation method and replaces it with independent management. This allows autonomous implementation of better memory usage patterns, such as memory pools, pre-allocation, etc. This way, no system call is required for every memory allocation.

1. Design thinking

  • The memory allocation algorithm adopts Google's TCMalloc算法. Each thread will maintain an independent memory pool on its own. When allocating memory, it will be allocated from this memory pool first. When the memory pool is insufficient, it will apply to the global memory pool for locking, reducing system calls. And avoid lock competition between different threads on the global memory pool

  • Divide the memory specifications into finer details and manage them hierarchically to reduce the granularity of locks.

  • When the object memory is recycled, it is not actually released, but is simply put back into a pre-allocated large block of memory for reuse. Only when the memory is too idle, it will try to return part of the memory to the operating system to reduce the overall overhead.

2. Assign components

Go's memory management components mainly include: mspan, mcache, mcentralandmheap

e47e9784410af736bfd9941012738b78.png

Memory management unit: mspan

mspanIt is the basic unit of memory management. The structure contains two fields, nextand prev, which point to the previous and next mspan respectively. Each mspanmanages npagesa page with a size of 8KB. A span is composed of multiple pages. Here The pages are not memory pages in the operating system, they are integer multiples of operating system memory pages. pageIt is the basic unit of memory storage, and the "object" is placed pagein it .

type mspan struct {
 next *mspan // 后指针
 prev *mspan // 前指针
 startAddr uintptr // 管理页的起始地址,指向page
 npages    uintptr // 页数
 spanclass   spanClass // 规格
 ...
}

type spanClass uint8

Go has 68 spanClasses of different sizes for allocation of small objects

const _NumSizeClasses = 68
var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536,1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768}
4cae535fdbc9a2ce5c2da035f31d924a.png

If allocated according to spanClass with serial number 1 (object specification is 8B), each span occupies the number of bytes of the heap: 8k, mspan can save 1024 objects

If allocated according to spanClass with serial number 2 (object specification is 16B), each span occupies the number of bytes of the heap: 8k, mspan can save 512 objects

If allocated according to spanClass with serial number 67 (object specification is 32K), each span occupies the number of bytes in the heap: 32k, mspan can save 1 object

Field meaning:

  • class: class ID, each span structure has a class ID, indicating the type of objects that the span can handle

  • bytes/obj: This class represents the number of bytes of the object

  • bytes/span: The number of bytes occupied by each span in the heap, that is, the number of pages * page size

  • objects: The number of objects that can be allocated to each span, that is, (bytes/spans)/(bytes/obj)

  • waste bytes: memory fragmentation generated by each span, that is, (bytes/spans)% (bytes/obj)

When an object larger than 32k appears, a special span will be allocated directly from the heap. The type (class) of this special span is 0 and only contains a large object.

Thread cache: mcache

mcache manages the mspan locally cached by the thread. Each goroutine-bound P has a mcachefield.

type mcache struct {
    alloc [numSpanClasses]*mspan
}

_NumSizeClasses = 68
numSpanClasses = _NumSizeClasses << 1

mcacheUsed Span Classesas an index to manage multiple allocations mspan, it contains all specifications mspan. It is _NumSizeClasses2 times, that is 68*2=136, *2 is to divide spanClass into two types: with pointers and without pointers, which is convenient for garbage collection. For each specification, there are 2 mspans, one mspan does not contain pointers and the other mspan contains pointers. For pointerless objects, mspanthere is no need to further scan whether it refers to other active objects during garbage collection.

mcacheThere are no resources during initialization mspan. They will be dynamically mcentralapplied for during use and will be cached later. When the object size is less than or equal to 32KB, mcachethe corresponding specifications are used mspanfor allocation.

Central cache: mcentral

mcentral manages the global mspan for use by all threads. The global mheap variable contains the central field. Each mcentral structure is maintained within the mheap structure.

type mcentral struct {
 spanclass spanClass // 指当前规格大小

 partial [2]spanSet // 有空闲object的mspan列表
 full    [2]spanSet // 没有空闲object的mspan列表
}

Each mcentral manages mspan of a spanClass, and manages mspans with free space and mspan without free space separately. Partial and full 的数据类型为spanSet represent mspanssets. mspans can be obtained through pop and push.

type spanSet struct {
    spineLock mutex
    spine     unsafe.Pointer // 指向[]span的指针
    spineLen  uintptr        // Spine array length, accessed atomically
    spineCap  uintptr        // Spine array cap, accessed under lock

    index headTailIndex  // 前32位是头指针,后32位是尾指针
}

Let’s briefly talk about mcachethe process of mcentralacquisition and return mspan:

  • partialAcquire; lock, find an available one from the linked list mspan; delete it from partialthe linked list; add the removed one mspanto fullthe linked list; mspanreturn it to the working thread and unlock it.

  • Return; lock mspan, fulldelete from linked list; mspanadd to partiallinked list, unlock.

Page heap: mheap

mheap manages all dynamically allocated memory of Go. It can be considered as the entire heap space held by the Go program and is globally unique.

var mheap_ mheap
type mheap struct {
    lock      mutex    // 全局锁
    pages     pageAlloc // 页面分配的数据结构
    allspans []*mspan // 所有通过 mheap_ 申请的mspans
  // 堆
    arenas [1 << arenaL1Bits]*[1 << arenaL2Bits]*heapArena
 
  // 所有中心缓存mcentral
    central [numSpanClasses]struct {
        mcentral mcentral
        pad      [cpu.CacheLinePadSize - unsafe.Sizeof(mcentral{})%cpu.CacheLinePadSize]byte
    }
    ...
}

All mcentralcollections are stored in mheap. mheapThe area in arenais an abstraction of heap memory. The runtime will 8KBregard it as a page. These memory pages store all objects initialized on the heap. The runtime uses a two-dimensional runtime.heapArena array to manage all memory. Each runtime.heapArena manages 64MB of memory.

When applying for memory, if there is no memory of suitable size available through mcacheand in sequence mcentral, then it will mheapapply for a piece of memory from . Then divide it into some lists according to the specified specifications, and add them to the back mcentralof the same specification size非空闲列表

3. Allocation process

Small object [0, 32KB]: Try thread cache, central cache, and heap allocation memory in sequence

Large objects (32KB, +∞): try to allocate memory directly on the heap

Object with memory escape: directly try to allocate memory on the heap

The following is a detailed introduction to the allocation process of small objects:

  • First by calculating the size specifications used

  • Then use mcachethe block allocation of the corresponding size specification in the thread cache.

  • If mcentralthere is no available block in the central cache, it is mheapapplied to the heap and the most suitable one is found according to the algorithm mspan.

  • If the requested mspanpage exceeds the requested size, it will be divided according to demand to return the number of pages required by the user. The remaining pages form a new mspan and are placed back into the mheap's free list.

  • If there is no span available in mheap, request a new series of pages from the operating system (minimum 1MB)

c58e7d2a8cd6b763598a47b24af911d1.png

Finally, let me advertise my original Go interview booklet. If you are engaged in Go-related development, you are welcome to scan the code to buy it. The current buyout is 10 yuan. Add the WeChat payment screenshot below to send an additional copy of your own recorded Go interview question explanation video.

c92a406bc83f413722714a22b53a2069.jpeg

3fa7f5fe7d3fe5c10c7d159da5398313.png

If it is helpful to you, please help me click to watch or forward it. Welcome to follow my official account

Guess you like

Origin blog.csdn.net/caspar_notes/article/details/133781892
Recommended