Go 1.26.4 超深度分析 --- Runtime GC 垃圾收集 (mgc*.go + mbitmap.go)
核心源码:
runtime/mgc.go(2333行) +runtime/mgcmark.go(1792行) +runtime/mgcpacer.go(1539行) +runtime/mgcscavenge.go(1414行) +runtime/mgcsweep.go(1018行) +runtime/mbitmap.go(1975行)
一、GC 模块定位
Go GC 采用并发标记-清除(Concurrent Mark-Sweep)算法:
- 非分代:不做新生代/老年代区分
- 非压缩:不做内存搬迁
- 精确:类型信息完整,无保守扫描
- 写屏障:混合写屏障 (Hybrid Write Barrier)
二、GC 四阶段
#mermaid-svg-kZpEhSjtxuAOWqqk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kZpEhSjtxuAOWqqk .error-icon{fill:#552222;}#mermaid-svg-kZpEhSjtxuAOWqqk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kZpEhSjtxuAOWqqk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kZpEhSjtxuAOWqqk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kZpEhSjtxuAOWqqk .marker.cross{stroke:#333333;}#mermaid-svg-kZpEhSjtxuAOWqqk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kZpEhSjtxuAOWqqk p{margin:0;}#mermaid-svg-kZpEhSjtxuAOWqqk defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-kZpEhSjtxuAOWqqk g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-kZpEhSjtxuAOWqqk g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-kZpEhSjtxuAOWqqk g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-kZpEhSjtxuAOWqqk g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-kZpEhSjtxuAOWqqk g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-kZpEhSjtxuAOWqqk .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-kZpEhSjtxuAOWqqk .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-kZpEhSjtxuAOWqqk .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-kZpEhSjtxuAOWqqk .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-kZpEhSjtxuAOWqqk .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-kZpEhSjtxuAOWqqk .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-kZpEhSjtxuAOWqqk .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-kZpEhSjtxuAOWqqk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kZpEhSjtxuAOWqqk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kZpEhSjtxuAOWqqk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kZpEhSjtxuAOWqqk .edgeLabel .label text{fill:#333;}#mermaid-svg-kZpEhSjtxuAOWqqk .label div .edgeLabel{color:#333;}#mermaid-svg-kZpEhSjtxuAOWqqk .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-kZpEhSjtxuAOWqqk .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-kZpEhSjtxuAOWqqk .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-kZpEhSjtxuAOWqqk .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-kZpEhSjtxuAOWqqk .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-kZpEhSjtxuAOWqqk .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kZpEhSjtxuAOWqqk .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kZpEhSjtxuAOWqqk #statediagram-barbEnd{fill:#333333;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kZpEhSjtxuAOWqqk .cluster-label,#mermaid-svg-kZpEhSjtxuAOWqqk .nodeLabel{color:#131300;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-kZpEhSjtxuAOWqqk .note-edge{stroke-dasharray:5;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-note text{fill:black;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram-note .nodeLabel{color:black;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagram .edgeLabel{color:red;}#mermaid-svg-kZpEhSjtxuAOWqqk #dependencyStart,#mermaid-svg-kZpEhSjtxuAOWqqk #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-kZpEhSjtxuAOWqqk .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kZpEhSjtxuAOWqqk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 正常运行
GC触发
(STW: 清除上轮残留)
启用写屏障
(STW结束)
标记完成
(STW: 刷新缓存)
禁用写屏障
(STW结束)
清除完成
_GCoff
SweepTermination
MarkPhase
MarkTermination
SweepPhase
正常分配
无写屏障
并发标记
写屏障启用
Mutator协助
并发清除
回收白色对象
| 阶段 | STW | 写屏障 | 描述 |
|---|---|---|---|
| SweepTermination | ✅ | ❌ | 清除上轮未完成的 span |
| Mark Phase | ❌ | ✅ | 并发标记根+堆对象 |
| Mark Termination | ✅ | ❌ | 刷新 mcaches,计算下轮阈值 |
| Sweep Phase | ❌ | ❌ | 并发清除,回收白色对象 |
三、GC 触发条件 (mgc.go)
go
type gcTrigger struct {
kind gcTriggerKind
now int64
}
const (
gcTriggerHeap gcTriggerKind = iota // 堆内存增长到阈值
gcTriggerTime // 2分钟未GC
gcTriggerCycle // 强制完整GC (runtime.GC())
)
func (t gcTrigger) test() bool {
switch t.kind {
case gcTriggerHeap:
// 堆大小 ≥ GOGC * (上轮存活大小 + 栈大小)
return memstats.heapLive >= memstats.gcTrigger
case gcTriggerTime:
// 距上次GC超过 forcegcperiod (2分钟)
return lastgc + forcegcperiod < now
case gcTriggerCycle:
return true // 总是触发
}
}
GOGC 触发公式
Goal = 上轮存活大小 × (1 + GOGC/100)
当 heapLive ≥ Goal → 触发 GC
GOGC=100 (默认) → 堆增长100%时触发
GOGC=off → 禁用GC (仅在极端场景使用)
四、GC 标记阶段 (mgcmark.go)
4.1 三色标记法
| 颜色 | 含义 | GC 状态 |
|---|---|---|
| 白色 | 未标记(可能被回收) | 初始状态 |
| 灰色 | 已标记但未扫描(子引用未追踪) | 在工作队列中 |
| 黑色 | 已标记且已扫描(子引用已追踪) | 存活 |
#mermaid-svg-54Thcu7xpREkHWVP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-54Thcu7xpREkHWVP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-54Thcu7xpREkHWVP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-54Thcu7xpREkHWVP .error-icon{fill:#552222;}#mermaid-svg-54Thcu7xpREkHWVP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-54Thcu7xpREkHWVP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-54Thcu7xpREkHWVP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-54Thcu7xpREkHWVP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-54Thcu7xpREkHWVP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-54Thcu7xpREkHWVP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-54Thcu7xpREkHWVP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-54Thcu7xpREkHWVP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-54Thcu7xpREkHWVP .marker.cross{stroke:#333333;}#mermaid-svg-54Thcu7xpREkHWVP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-54Thcu7xpREkHWVP p{margin:0;}#mermaid-svg-54Thcu7xpREkHWVP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-54Thcu7xpREkHWVP .cluster-label text{fill:#333;}#mermaid-svg-54Thcu7xpREkHWVP .cluster-label span{color:#333;}#mermaid-svg-54Thcu7xpREkHWVP .cluster-label span p{background-color:transparent;}#mermaid-svg-54Thcu7xpREkHWVP .label text,#mermaid-svg-54Thcu7xpREkHWVP span{fill:#333;color:#333;}#mermaid-svg-54Thcu7xpREkHWVP .node rect,#mermaid-svg-54Thcu7xpREkHWVP .node circle,#mermaid-svg-54Thcu7xpREkHWVP .node ellipse,#mermaid-svg-54Thcu7xpREkHWVP .node polygon,#mermaid-svg-54Thcu7xpREkHWVP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-54Thcu7xpREkHWVP .rough-node .label text,#mermaid-svg-54Thcu7xpREkHWVP .node .label text,#mermaid-svg-54Thcu7xpREkHWVP .image-shape .label,#mermaid-svg-54Thcu7xpREkHWVP .icon-shape .label{text-anchor:middle;}#mermaid-svg-54Thcu7xpREkHWVP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-54Thcu7xpREkHWVP .rough-node .label,#mermaid-svg-54Thcu7xpREkHWVP .node .label,#mermaid-svg-54Thcu7xpREkHWVP .image-shape .label,#mermaid-svg-54Thcu7xpREkHWVP .icon-shape .label{text-align:center;}#mermaid-svg-54Thcu7xpREkHWVP .node.clickable{cursor:pointer;}#mermaid-svg-54Thcu7xpREkHWVP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-54Thcu7xpREkHWVP .arrowheadPath{fill:#333333;}#mermaid-svg-54Thcu7xpREkHWVP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-54Thcu7xpREkHWVP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-54Thcu7xpREkHWVP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-54Thcu7xpREkHWVP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-54Thcu7xpREkHWVP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-54Thcu7xpREkHWVP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-54Thcu7xpREkHWVP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-54Thcu7xpREkHWVP .cluster text{fill:#333;}#mermaid-svg-54Thcu7xpREkHWVP .cluster span{color:#333;}#mermaid-svg-54Thcu7xpREkHWVP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-54Thcu7xpREkHWVP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-54Thcu7xpREkHWVP rect.text{fill:none;stroke-width:0;}#mermaid-svg-54Thcu7xpREkHWVP .icon-shape,#mermaid-svg-54Thcu7xpREkHWVP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-54Thcu7xpREkHWVP .icon-shape p,#mermaid-svg-54Thcu7xpREkHWVP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-54Thcu7xpREkHWVP .icon-shape .label rect,#mermaid-svg-54Thcu7xpREkHWVP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-54Thcu7xpREkHWVP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-54Thcu7xpREkHWVP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-54Thcu7xpREkHWVP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} scan()
扫描子引用
子引用变灰
白色对象
(未标记)
灰色对象
(已标记未扫描)
黑色对象
(已标记已扫描)
4.2 写屏障 --- 混合写屏障 (Hybrid Write Barrier)
Go 1.8+ 使用混合写屏障,减少 STW 时间:
go
// 混合写屏障伪代码:
func writeBarrier(slot *unsafe.Pointer, ptr unsafe.Pointer) {
// 1. 标记被覆盖的旧指针 (Dijkstra 式)
shade(*slot)
// 2. 标记新写入的指针 (Yuasa 式)
shade(ptr)
}
为什么需要两种:
- Dijkstra (shade新值): 防止新对象丢失
- Yuasa (shade旧值): 防止快照时对象丢失
- 混合: 两全其美,不需要 STW 来重新扫描栈
五、GC 工作队列 --- gcWork (mgcmark.go)
go
type gcWork struct {
wbuf1, wbuf2 *workbuf // 双缓冲 (生产/消费分离)
bytesMarked uint64 // 标记的字节数
flushedWork bool // 是否有数据刷到全局
}
gcWork 生产-消费模式
#mermaid-svg-bCDnwV3K5cH0NHF3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bCDnwV3K5cH0NHF3 .error-icon{fill:#552222;}#mermaid-svg-bCDnwV3K5cH0NHF3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bCDnwV3K5cH0NHF3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .marker.cross{stroke:#333333;}#mermaid-svg-bCDnwV3K5cH0NHF3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bCDnwV3K5cH0NHF3 p{margin:0;}#mermaid-svg-bCDnwV3K5cH0NHF3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .cluster-label text{fill:#333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .cluster-label span{color:#333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .cluster-label span p{background-color:transparent;}#mermaid-svg-bCDnwV3K5cH0NHF3 .label text,#mermaid-svg-bCDnwV3K5cH0NHF3 span{fill:#333;color:#333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .node rect,#mermaid-svg-bCDnwV3K5cH0NHF3 .node circle,#mermaid-svg-bCDnwV3K5cH0NHF3 .node ellipse,#mermaid-svg-bCDnwV3K5cH0NHF3 .node polygon,#mermaid-svg-bCDnwV3K5cH0NHF3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bCDnwV3K5cH0NHF3 .rough-node .label text,#mermaid-svg-bCDnwV3K5cH0NHF3 .node .label text,#mermaid-svg-bCDnwV3K5cH0NHF3 .image-shape .label,#mermaid-svg-bCDnwV3K5cH0NHF3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-bCDnwV3K5cH0NHF3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bCDnwV3K5cH0NHF3 .rough-node .label,#mermaid-svg-bCDnwV3K5cH0NHF3 .node .label,#mermaid-svg-bCDnwV3K5cH0NHF3 .image-shape .label,#mermaid-svg-bCDnwV3K5cH0NHF3 .icon-shape .label{text-align:center;}#mermaid-svg-bCDnwV3K5cH0NHF3 .node.clickable{cursor:pointer;}#mermaid-svg-bCDnwV3K5cH0NHF3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .arrowheadPath{fill:#333333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bCDnwV3K5cH0NHF3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bCDnwV3K5cH0NHF3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bCDnwV3K5cH0NHF3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bCDnwV3K5cH0NHF3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bCDnwV3K5cH0NHF3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bCDnwV3K5cH0NHF3 .cluster text{fill:#333;}#mermaid-svg-bCDnwV3K5cH0NHF3 .cluster span{color:#333;}#mermaid-svg-bCDnwV3K5cH0NHF3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bCDnwV3K5cH0NHF3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bCDnwV3K5cH0NHF3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-bCDnwV3K5cH0NHF3 .icon-shape,#mermaid-svg-bCDnwV3K5cH0NHF3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bCDnwV3K5cH0NHF3 .icon-shape p,#mermaid-svg-bCDnwV3K5cH0NHF3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bCDnwV3K5cH0NHF3 .icon-shape .label rect,#mermaid-svg-bCDnwV3K5cH0NHF3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bCDnwV3K5cH0NHF3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bCDnwV3K5cH0NHF3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bCDnwV3K5cH0NHF3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 全局
Per-P
满
空
gcWork
wbuf1 (主缓冲)
wbuf2 (备用)
full buffers
empty buffers
六、GC Pacer --- 调步器 (mgcpacer.go)
调步器控制 GC 的速率,确保:
- GC 完成时堆大小不超过目标
- Mutator 协助标记的工作量合理分配
go
type gcControllerState struct {
heapGoal atomic.Int64 // 目标堆大小
heapLive atomic.Int64 // 当前存活堆大小
triggerRatio float64 // 触发比率
goalRatio float64 // 目标比率
assistWorkPerByte atomic.Int64 // 协助工作/分配字节比
assistBytesPerWork atomic.Int64 // 协助字节/工作比
}
GC Assist --- Mutator 协助
当 goroutine 分配内存时,如果 gcAssistBytes < 0,必须先做标记工作补偿:
go
func gcAssistAlloc(gp *g, dataSize uintptr) {
// 1. 计算需要补偿的扫描工作量
assistWorkPerByte := gcController.assistWorkPerByte.Load()
debtBytes := -gp.gcAssistBytes
scanWork := int64(float64(debtBytes) * assistWorkPerByte)
// 2. 执行扫描工作 (drain gcWork)
gcDrainN(&pp.gcw, scanWork)
// 3. 更新信用
gp.gcAssistBytes += repayBytes
}
七、GC 清除阶段 (mgcsweep.go)
7.1 清除方式
| 方式 | 触发时机 | 描述 |
|---|---|---|
| 惰性清除 | 分配时 | mcentral.findsweep → 清除一个 span |
| 后台清除 | 后台 goroutine | sweepone → 逐个清除 |
| 主动清除 | STW | flushallmcaches → 刷新所有 mcaches |
7.2 清除流程
go
func sweepone() uintptr {
// 1. 从 sweepSpans 获取一个 span
// 2. 检查 span 中对象的标记位
// 3. 未标记的对象 → 释放 (free)
// 4. 全部未标记 → span 归还 mheap
// 5. 部分未标记 → span 放回 mcentral.partial
}
八、GC 回收 --- Scavenger (mgcscavenge.go)
Scavenger 负责将空闲内存归还给操作系统:
go
func (s *scavengerState) start() {
// 后台 goroutine 定期回收
// 回收条件: 空闲内存超过 5% 目标
}
func (s *scavengerState) scavenge() {
// 1. 扫描 pageAlloc 找空闲页
// 2. 调用 sysUnused(madvise MADV_DONTNEED)
// 3. 内存归还给 OS (但虚拟地址仍保留)
}
九、GC 位图 --- mbitmap.go
堆位图结构
每个 span 有两种位图:
1. mark bitmap: 标记位 (GC 用)
- bit=1: 对象已标记(黑色/灰色)
- bit=0: 对象未标记(白色)
2. allocation bitmap: 分配位
- bit=1: 对象已分配
- bit=0: 对象空闲
十、GC 完整时序
Scavenger Mutator Assists Mark Workers GC Controller Mutator Goroutines Scavenger Mutator Assists Mark Workers GC Controller Mutator Goroutines #mermaid-svg-4CIfB2Zk2gK5VUAc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4CIfB2Zk2gK5VUAc .error-icon{fill:#552222;}#mermaid-svg-4CIfB2Zk2gK5VUAc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4CIfB2Zk2gK5VUAc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4CIfB2Zk2gK5VUAc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4CIfB2Zk2gK5VUAc .marker.cross{stroke:#333333;}#mermaid-svg-4CIfB2Zk2gK5VUAc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4CIfB2Zk2gK5VUAc p{margin:0;}#mermaid-svg-4CIfB2Zk2gK5VUAc .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4CIfB2Zk2gK5VUAc text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-4CIfB2Zk2gK5VUAc .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4CIfB2Zk2gK5VUAc .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-4CIfB2Zk2gK5VUAc .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-4CIfB2Zk2gK5VUAc .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-4CIfB2Zk2gK5VUAc #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-4CIfB2Zk2gK5VUAc .sequenceNumber{fill:white;}#mermaid-svg-4CIfB2Zk2gK5VUAc #sequencenumber{fill:#333;}#mermaid-svg-4CIfB2Zk2gK5VUAc #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-4CIfB2Zk2gK5VUAc .messageText{fill:#333;stroke:none;}#mermaid-svg-4CIfB2Zk2gK5VUAc .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4CIfB2Zk2gK5VUAc .labelText,#mermaid-svg-4CIfB2Zk2gK5VUAc .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-4CIfB2Zk2gK5VUAc .loopText,#mermaid-svg-4CIfB2Zk2gK5VUAc .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-4CIfB2Zk2gK5VUAc .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4CIfB2Zk2gK5VUAc .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4CIfB2Zk2gK5VUAc .noteText,#mermaid-svg-4CIfB2Zk2gK5VUAc .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-4CIfB2Zk2gK5VUAc .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4CIfB2Zk2gK5VUAc .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4CIfB2Zk2gK5VUAc .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4CIfB2Zk2gK5VUAc .actorPopupMenu{position:absolute;}#mermaid-svg-4CIfB2Zk2gK5VUAc .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-4CIfB2Zk2gK5VUAc .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4CIfB2Zk2gK5VUAc .actor-man circle,#mermaid-svg-4CIfB2Zk2gK5VUAc line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-4CIfB2Zk2gK5VUAc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} heapLive ≥ gcTrigger par并发标记 par并发清除 STW: SweepTermination启用写屏障STW结束: MarkPhase开始gcDrain() 扫描灰色对象gcAssistAlloc() 协助标记写屏障 shade(旧值+新值)gcMarkDone() → 标记完成STW: MarkTerminationflushallmcaches()禁用写屏障STW结束: SweepPhase惰性清除 (分配时)回收空闲内存→OS
十一、设计模式总结
| # | 模式 | 体现 |
|---|---|---|
| 1 | 三色标记 | 白/灰/黑 三色不变式 |
| 2 | 混合写屏障 | Dijkstra+Yuasa 双shade |
| 3 | 并发标记 | Workers+Assists 并行 |
| 4 | Mutator 协助 | gcAssistAlloc 分配补偿 |
| 5 | 调步器 | PID 式速率控制 |
| 6 | 双缓冲 | gcWork wbuf1/wbuf2 |
| 7 | 惰性清除 | 分配时顺便清除 |
| 8 | 后台回收 | Scavenger madvise |
| 9 | 位图标记 | mark bitmap + alloc bitmap |
| 10 | STW 最小化 | 仅在标记启停时 STW |
| 11 | 分布式终止 | gcMarkDone 无全局锁 |
| 12 | GOGC 反馈 | 目标堆大小动态调整 |