【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 反馈 目标堆大小动态调整
相关推荐
weixin_3077791319 分钟前
Python写入Shell文件使用Linux系统的换行符
linux·开发语言·python·自动化
zmzb010338 分钟前
Python课后习题训练记录Day130
开发语言·python
阿里嘎多学长1 小时前
2026-06-13 GitHub 热点项目精选
开发语言·程序员·github·代码托管
xiaoshuaishuai81 小时前
C# 委托与事件
开发语言·c#
kmblack11 小时前
javascript计算年龄
开发语言·javascript·ecmascript
肖爱Kun2 小时前
STL标准模块库操作
开发语言·音视频
Song_da_da_2 小时前
C# 接口(Interface)深度解析:规范、解耦与灵活扩展
开发语言·c#
政沅同学2 小时前
基于 C# WPF + HALCON 的工业视觉算法工具框架(开源)
开发语言·c#·wpf
影寂ldy2 小时前
C#WinForm 窗体基础(入口、部分类、属性、生命周期事件)
开发语言·c#
2301_781833522 小时前
Python 正则表达式入门教程
开发语言·python·正则表达式