内存分配
大约 2 分钟
内存分配
一、堆内存里面是分块的
- Arena Runtime将堆内存划分为一个个的arena(每个64MB)。物理存储内存。
- Page 每个Arena包含8192个page,每个page大小8kb。物理存储内存。
- Span go语言特定内存管理单位。多个连续Page之间按照不同大小规格划分出逻辑上的Span(链表)。
二、程序请求内存的时候直接从预置的大小规格拿出来的
程序请求分配内存的时候,有大有小,为了降低碎片化内存带来的不良影响(空间浪费),采用Tcmalloc内存分配器类似的算法。Tcmalloc内存分配器类似的算法指的是将内存页按照预置的大小规格划分成多块(Span)(用链表记录),程序请求内存时候,直接将匹配的大小规格的给过去(67种规格 8*8 bit (8字节)-32kb)。
三、底层的runtime的数据结构
- mheap
// mheap.go
// 管理所有推内存
// 主堆内存分配器。
type mheap struct {
_ sys.NotInHeap
central [numSpanClasses]struct {
// mcentral数组
// 1个mcentral映射1个mspan
// mcentral记录是否需要GC扫描、是否已经清扫
mcentral mcentral
...
}
...
}
type mcentral struct {
spanclass spanClass
...
}
- heapArena
// mheap.go
// 对应1个arena的管理信息
type heapArena struct {
_ sys.NotInHeap
// pageMarks是一个位图
// 在标记期间,写入是原子性的操作,读取是非原子性且无锁
//
// 这用于快速找到可以被释放的整个跨度Span
pageMarks [pagesPerArena / 8]uint8
...
}
- mspan
// mheap.go
// 对应1个span的管理信息
type mspan struct {
_ sys.NotInHeap
...
}
// 不管堆内存还是栈内存都是mspan只不状态不同
type mSpanState uint8
const (
mSpanDead mSpanState = iota
mSpanInUse // 堆内存 allocated for garbage collected heap
mSpanManual // 栈内存 allocated for manual management (e.g., stack allocator)
)
- 程序申请内存,本质是P从mheap之中拿内存,这里因为避免多个P之间频繁加锁避免竞争,设计了mcache也就是P的本地缓存,P在本地找不到才会去mcentral拿到本地花。