NOTE
3.9 Golang堆管理
1. 堆是什么 - 空间大,数据存放时间较长。堆在低地址,从低地址向高地址增长 - 分配:程序员手动分配 - 回收:GC Go的内存管理是runtime,也就是说并不是每次内存分配都需要进行系统调用。 采用的算法是 TCMalloc 算法,即 Thread-Caching Malloc 。 他把可用
这是历史学习笔记,可能存在过时或不完整的理解。
1. 堆是什么
- 空间大,数据存放时间较长。堆在低地址,从低地址向高地址增长
- 分配:程序员手动分配
- 回收:GC
Go的内存管理是runtime,也就是说并不是每次内存分配都需要进行系统调用。
采用的算法是
TCMalloc算法,即Thread-Caching Malloc。 他把小对象分配组织成多级缓存:每个P通过mcache维护本地可用的mspan,进行内存分配时优先从本地缓存分配,不足时再从mcentral等全局结构获取,以减少并发竞争
2. 堆内存
Go启动时会向操作系统申请内存,内存划分如下

- arena:堆地址空间按arena分段管理,具体大小和层级与架构以及runtime实现有关
- bitmap:记录堆对象中的指针等GC元数据,具体存储布局由runtime实现
- spans:用于从堆地址定位对应的mspan
3. 内存管理单元

- mspan:内存管理的基本单元
- 由连续的页组成
- 按照Size Class的大小分成若干个object,每个object可存储一个对象。

4. 内存分配器
4.1. mcache
每个P都会绑定一个mcache,本地缓存可用的mspan资源,这样就可以直接给Goroutine分配,因为mcache由单个P使用,所以本地分配不需要加锁。
4.2. mcentral
当P的mcache中没有合适(也就是特定大小的)的mspan时就会从mcentral获取。mcentral被多个P共同使用,因此访问时需要同步 为所有mcache提供切分好的mspan资源。每个central保存一种特定大小的全局mspan列表,包括已分配出去的和未分配出去的。
4.3. mheap
代表Go程序持有的所有堆空间,Go程序使用一个mheap的全局对象_mheap来管理堆内存。 当mcentral没有空闲的mspan时,会向mheap申请。而mheap没有资源时,会向操作系统申请新内存
5. 逃逸分析
6. 内存分配流程
根据逃逸分析.md的结果能在栈上分配就在栈上,否则考虑堆 根据对象的大小,分成三类:小对象(小于等于16B)、一般对象(大于16B,小于等于32KB)、大对象(大于32KB)。
-
32KB 的对象,直接从mheap上分配;
- <=16B 的对象使用mcache的tiny分配器分配;
- (16B,32KB] 的对象,首先计算对象的规格大小,然后使用mcache中相应规格大小的mspan分配;
- 如果mcache没有相应规格大小的mspan,则向mcentral申请
- 如果mcentral没有相应规格大小的mspan,则向mheap申请
- 如果mheap中也没有合适大小的mspan,则向操作系统申请

讨论
使用 GitHub 账号参与讨论,评论会保存在 GitHub Issues 中。在 GitHub 查看