Cloud Native Foundation - Go GC
Heap 管理
Allocator(向OS申请)初始化连续内存块作为 HeapMutator申请内存,Allocator 从 Heap 中未分配的区域中分割小的内存块- 用
链表将已分配内存连接起来 - 内存块
元数据:大小、是否使用、下一个内存块的地址 Collector会扫描 Heap,将不再被使用的内存设置为unused
内存分配
TCMalloc
TC =
Thread Caching
- page:内存
页,大小为8k,Go与OS之间的内存申请和内存释放,都是以 page 为单位的 - span:内存
块,一个或者多个连续的 page 组成一个 span - sizeclass:空间规格,每个
span都带有一个 sizeclass,标记着该 span 中的 page 该如何使用- sizeclass -
8,16,32,48,64,80…
- sizeclass -
- object:对象,用来存储一个变量数据的内存空间
- span 在
初始化时,会被切割成一堆等大的 object - 如果 object 的大小为 16B,Span list 1 中的 span 为 8k,该 span 中的 page 会被初始化为 8k/16B = 512 Object
- 所谓
内存分配,即对象分配
- span 在
- 对象分配流程
- 小对象(
0 ~ 256KB)-32 pagesThreadCache->CentralCache->HeapPage- ThreadCache:大部分时候缓存都是足够的
- CentralCache + HeapPage:
无系统调用+无锁分配,分配效率非常高效
- 中对象(
256KB ~ 1MB)-32 ~ 128 pages- 直接在
HeapPage中选择适当的大小即可
- 直接在
- 大对象(
> 1MB)- 从
Large span set选择合适数量的 page 组成 span,用来存储数据
- 从
- 小对象(
Go
从 TCMalloc 衍生,做了
增强
mcache- sizeclass:
1 ~ 66,每个 class两个 span- 134- 增强(减少扫描,加快 GC):一个存
指针,一个存直接引用(存直接引用的 span无需 GC)
- 增强(减少扫描,加快 GC):一个存
- Span 大小为
8KB,按照 Span class 大小切分
- sizeclass:
mcentral- 当 Span 内的所有内存都被占用,没有剩余空间继续分配对象,mcache 会向 mcentral 申请 1 个 Span
- 如果 mcentral 没有符合条件的 Span,mcentral 会向 mheap 申请 Span
mheap- 当 mheap 没有足够的内存时,mheap 会向 OS 申请内存
- mheap 将 Span 组织成
树结构,然后将 Span 分配到heapArena进行管理
内存回收
mark-sweep(利用三色标记算法,从GC Root开始遍历扫描所有引用的对象),会发生短暂STW
GC 结构
描述 span 的结构体
allocBits:记录 Span 中每块内存的分配情况(分配时标记)gcmarkBits:记录 Span 中每块内存的引用情况(Mark 阶段会更新)
对照 allocBits 和 gcmarkBits:
已分配 + 未引用
GC 流程
Go GC的大部分处理是和用户代码是并行的(≈ Java 中的CMS)
三色标记
白色:
垃圾;黑色:活跃;灰色:待定
递归:一开始全是白色,最后直到没有灰色
对于
黑色对象,如果在Mark 阶段发生了写操作,写屏障会在真正赋值前将新对象标记为灰色
Mark 阶段,新分配的对象会被标记为黑色再返回
触发机制
内存分配量:阈值 = 上次 GC 内存分配量 *内存增长率(GOGC,默认100),即每当内存扩大一倍启动 GC定时:默认2 分钟手动:runtime.GC()
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.

















