GO内存
GO机制
分块
调用mmap()向OS申请一块大内存,再将内存划分成大块,称为mspan
再将msoan划分为特定大小的小块,用于对象分配
- noscan mspan 分配不包含指针的对象 -- GC不需要扫描
- scan mspan 分配包含指针的对象 -- GC需要扫描 根据对象的大小返回内存快
缓存
借鉴TCMalloc: thread caching 每个p包含一个mcache用于快速分配,用于为绑定 与p上的g分配对象 mcache 管理一组mspan 当mcache中的mspan分配完毕,向mcentral申请带有未分配块的mspan 当mspan中没有分配的对象,mspan会被缓存在mcentral中,而不是立即释放并归还给OS
分析和优化
- 小对象占比较高
- 分配路径长
Balanced GC
goroutine alloction buffer,使用base, end, top 指针维护
Bump point 风格对象分配:
- 通过操作指针完成对象分配,简单高效
- 无需和其他分配请求互斥
看上去有点像c++本质上是将多个小对象的分配合并成一次大对象分配
❓GAB对象分配导致内存释放被延迟 ✅ 移动GAB中的存活对象 - 当GAB总大小超过一定阈值,将其中存活的对象复制到另外分配的 Survivor GAB 中
- 原先的GAB可以释放,避免内存泄漏
- 本质:用copying GC 的算法管理小对象,根据对象生命周期使用不同的标记和清理策略
编译器
函数内联
将被调用函数的函数体的副本替换到调用位置上,同时重写代码以反映参数的绑定
- 消除函数调用开销:传参,保存寄存器
- 将过程间分析转化为过程内分析 缺点
- 函数体变大,instruction cache不友好
- 编译生成Go镜像变大
Go限制较多
Beast mode 调整函数内联策略,增加逃逸分析