【Go 1.26.4】(Part 3) Go 1.26.4 超深度分析 — Runtime GC 垃圾收集 (mgc*.go + mbitmap.go)

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 的速率,确保:

  1. GC 完成时堆大小不超过目标
  2. 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 反馈 目标堆大小动态调整
相关推荐
破茧蝴蝶2 小时前
Python分布式爬虫完整教程
开发语言·python
狗凯之家源码网2 小时前
全新 PHP 轻量客服聊天室源码深度评测
开发语言·php·聊天室系统
远离UE43 小时前
UE5 Substrate Thin Film 源码拆析
开发语言·javascript·ue5
keyipatience3 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习
栈帧之外4 小时前
【C++】STL之set
开发语言·c++
catchadmin5 小时前
免费可商用 PHP 管理后台 CatchAdmin V5.4.1 发布,新增 MCP 支持
开发语言·php
jimy16 小时前
c++的 Type Traits (二、更详细版本)
开发语言·c++
狗凯之家源码网6 小时前
纯 PHP+MySQL 应用市场系统源码实测!
开发语言·mysql·php
dishugj6 小时前
系统架构风险点、敏感点和权衡点的概念和区分
java·开发语言
geovindu7 小时前
rust:Memento Pattern(续)
开发语言·后端·设计模式·rust·行为模式·备忘录模