这是我参与「第三届青训营-后端场」笔记创作活动的的第2篇笔记。
分代GC(Generational GC)
-
分代假说(Generational hypothesis):most objects die young
-
Intuition:很多对象在分配出来后很快就不再使用了
-
每个对象都有年龄:经历过GC的次数
-
目的:针对年轻和老年的对象,制定不同的GC策略,降低整体内存管理的开销
-
不同年龄的对象处于heap的不同区域
-
年轻代(Young generation)
- 常规的对象分配
- 由于存活对象很少,可以采用 copying collection GC吞吐率很高
-
老年代(Old generation)
-
对象趋向于一直活着,反复复制开销较大
-
可以采用 mark-sweep collection
-
引用计数
- 每个对象都有一个与之关联的引用数目
- 对象存活的条件:当且仅当引用数大于0
- 优点
- 内存管理的操作被平摊到程序执行过程中
- 内存管理不需要了解runtime 的实现细节:C++智能指针(smart pointer)
- 缺点
-
维护引用计数的开销较大:通过原子操作保证对引用计数操作的原子性和可见性
-
无法回收环形数据结构-weak reference
-
内存开销:每个对象都引入的额外内存空间存储引用数目
-
回收内存时依然可能引发暂停
-
Go内存分配一分块
- 目标:为对象在heap上分配内存
- 提前将内存分块
- 调用系统调用map()向OS申请一大块内存,例如4MB
- 先将内存划分成大块,例如8 KB,称作mspan
- 再将大块继续划分成特定大小的小块,用于对象分配
- noscan mspan:分配不包含指针的对象-GC不需要扫描
- scan ms pan:分配包含指针的对象-GC需要扫描
- 对象分配:根据对象的大小,选择最合适的块返回
Go内存分配一缓存
- TCMalloc:thread caching
- 每个p包含一个mcache用于快速分配,用于为绑定于p上的g分配对象
- mcache管理一组mspan
- 当mcache中的mspan分配完毕,向mcentral申请带有未分配块的mspan
- 当mspan中没有分配的对象,mspan会被缓存在mcentral 中,而不是立刻释放并归还给OS