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 poolDivide 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
, mcentral
andmheap
Memory management unit: mspan
mspan
It is the basic unit of memory management. The structure contains two fields, next
and prev
, which point to the previous and next mspan respectively. Each mspan
manages npages
a 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. page
It is the basic unit of memory storage, and the "object" is placed page
in 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}
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 mcache
field.
type mcache struct {
alloc [numSpanClasses]*mspan
}
_NumSizeClasses = 68
numSpanClasses = _NumSizeClasses << 1
mcache
Used Span Classes
as an index to manage multiple allocations mspan
, it contains all specifications mspan
. It is _NumSizeClasses
2 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, mspan
there is no need to further scan whether it refers to other active objects during garbage collection.
mcache
There are no resources during initialization mspan
. They will be dynamically mcentral
applied for during use and will be cached later. When the object size is less than or equal to 32KB, mcache
the corresponding specifications are used mspan
for 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 mspans
sets. 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 mcache
the process of mcentral
acquisition and return mspan
:
partial
Acquire; lock, find an available one from the linked listmspan
; delete it frompartial
the linked list; add the removed onemspan
tofull
the linked list;mspan
return it to the working thread and unlock it.Return; lock
mspan
,full
delete from linked list;mspan
add topartial
linked 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 mcentral
collections are stored in mheap
. mheap
The area in arena
is an abstraction of heap memory. The runtime will 8KB
regard 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 mcache
and in sequence mcentral
, then it will mheap
apply for a piece of memory from . Then divide it into some lists according to the specified specifications, and add them to the back mcentral
of 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
mcache
the block allocation of the corresponding size specification in the thread cache.If
mcentral
there is no available block in the central cache, it ismheap
applied to the heap and the most suitable one is found according to the algorithmmspan
.If the requested
mspan
page 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)
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.
If it is helpful to you, please help me click to watch or forward it. Welcome to follow my official account