Go 语言是如何做内存分配的?
Go 语言是如何做内存分配的?
提示
题眼: 了解即可。
Go 的内存分配可以从堆和栈两个区域来理解:
- 栈上主要存放函数调用帧、局部变量、参数等,生命周期跟函数执行强相关。
- 堆上主要存放运行时动态分配、生命周期更长或无法静态确定的数据。
Go 运行时会根据对象大小采用不同的分配策略,通常可以把对象粗略分成三类:
| 类别 | 大小 |
|---|---|
| 微对象 | (0, 16B) |
| 小对象 | [16B, 32KB] |
| 大对象 | (32KB, +∞) |
Go 的分配器整体上和 TCMalloc 的多级缓存思路比较像,常见的几个层次包括:
mcache:每个P上的本地缓存,分配小对象时非常高效。mcentral:中心缓存,负责在不同本地缓存之间做补充。mheap:堆级别的内存管理,主要处理更大粒度的分配。
此外,Go 还会通过 size class、span 等机制管理不同大小的对象,尽量减少碎片并提高分配效率。
重要
参考答案:
Go 的内存分配核心可以抓两点。第一,它会尽量把能放在栈上的对象放在栈上,因为栈分配和回收都更便宜;第二,真正需要动态管理的对象才放到堆上,由运行时分配器和 GC 共同处理。
在具体实现上,Go 对不同大小的对象会走不同路径。小对象大多优先从 mcache 分配,因为它和 P 绑定,竞争很少,速度很快;本地缓存不够了再向 mcentral 申请;更大的对象则可能直接走 mheap。
这套设计的目标就是减少锁竞争、减少碎片,同时让高频的小对象分配尽量快。
相关信息
引申: 你了解过 TCMalloc 吗?为什么一个 struct 中相同类型的字段排在一起会提高内存利用率?
