本文档基于 Go 1.27+ 源码,深入解析内存分配与垃圾回收的底层实现原理,适合中高级 Go 开发者、架构师及大厂面试准备。
文章目录
-
- [1. 核心基础与面试前置知识](#1. 核心基础与面试前置知识)
-
- [1.1 内存布局基础](#1.1 内存布局基础)
- [1.2 对象生命周期](#1.2 对象生命周期)
- [1.3 编译器逃逸分析作用](#1.3 编译器逃逸分析作用)
- [1.4 GC 的设计目标与约束](#1.4 GC 的设计目标与约束)
- [1.5 Go 与 Java GC 的设计差异](#1.5 Go 与 Java GC 的设计差异)
- [1.6 大厂面试基础易错点](#1.6 大厂面试基础易错点)
- [2. Go 内存分配完整底层原理(重点深挖)](#2. Go 内存分配完整底层原理(重点深挖))
-
- [2.1 内存分配架构总览](#2.1 内存分配架构总览)
- [2.2 M/P/G 与内存调度的关系](#2.2 M/P/G 与内存调度的关系)
- [2.3 mcache 层详解](#2.3 mcache 层详解)
- [2.4 mcentral 层详解](#2.4 mcentral 层详解)
- [2.5 mspan 结构详解](#2.5 mspan 结构详解)
- [2.6 mheap 与 heapArena 详解](#2.6 mheap 与 heapArena 详解)
- [2.7 大小分类(Size Classes)](#2.7 大小分类(Size Classes))
- [2.8 分级分配策略详解](#2.8 分级分配策略详解)
-
- [2.8.1 微对象(Tiny Objects: 0 < size ≤ 16B,无指针)](#2.8.1 微对象(Tiny Objects: 0 < size ≤ 16B,无指针))
- [2.8.2 小对象(Small Objects: 16B < size ≤ 32KB)](#2.8.2 小对象(Small Objects: 16B < size ≤ 32KB))
- [2.8.3 大对象(Large Objects: size > 32KB)](#2.8.3 大对象(Large Objects: size > 32KB))
- [2.9 地址对齐与内存池设计](#2.9 地址对齐与内存池设计)
- [2.10 并发分配安全机制](#2.10 并发分配安全机制)
- [2.11 内存碎片成因与规避](#2.11 内存碎片成因与规避)
- [2.12 逃逸分析完整原理与编译器判定逻辑](#2.12 逃逸分析完整原理与编译器判定逻辑)
- [2.13 栈扩容与缩容机制](#2.13 栈扩容与缩容机制)
- [2.14 完整的对象分配流程图](#2.14 完整的对象分配流程图)
- [3. Go 垃圾回收完整底层实现原理(重点深挖)](#3. Go 垃圾回收完整底层实现原理(重点深挖))
-
- [3.1 Go GC 演进历史](#3.1 Go GC 演进历史)
- [3.2 三色标记法完整原理](#3.2 三色标记法完整原理)
- [3.3 漏标问题成因与解决方案](#3.3 漏标问题成因与解决方案)
- [3.4 GC 完整阶段详解](#3.4 GC 完整阶段详解)
-
- [阶段1: 标记预备(Sweep Termination)- STW](#阶段1: 标记预备(Sweep Termination)- STW)
- [阶段2: 并发标记(Concurrent Mark)](#阶段2: 并发标记(Concurrent Mark))
- [阶段3: 标记终止(Mark Termination)- STW](#阶段3: 标记终止(Mark Termination)- STW)
- [阶段4: 并发清扫(Concurrent Sweep)](#阶段4: 并发清扫(Concurrent Sweep))
- [3.5 STW 产生时机与性能影响](#3.5 STW 产生时机与性能影响)
- [3.6 GC Pacer 与触发机制](#3.6 GC Pacer 与触发机制)
- [3.7 GC 与 M/P/G 调度协同](#3.7 GC 与 M/P/G 调度协同)
- [3.8 并发清扫与内存归还](#3.8 并发清扫与内存归还)
- [3.9 内存回收与归还操作系统](#3.9 内存回收与归还操作系统)
- [3.10 大对象与 finalizer 处理](#3.10 大对象与 finalizer 处理)
- [3.11 写屏障原理图](#3.11 写屏障原理图)
- [3.12 STW 触发场景对比图](#3.12 STW 触发场景对比图)
- [4. Runtime 关键源码逐段解析](#4. Runtime 关键源码逐段解析)
-
- [4.1 mallocgc - 对象分配入口](#4.1 mallocgc - 对象分配入口)
- [4.2 mcache.refill - 补充 span](#4.2 mcache.refill - 补充 span)
- [4.3 mcentral.cacheSpan - 获取 span](#4.3 mcentral.cacheSpan - 获取 span)
- [4.4 mheap.alloc - 从堆分配](#4.4 mheap.alloc - 从堆分配)
- [4.5 gcStart - GC 开始](#4.5 gcStart - GC 开始)
- [4.6 gcDrain - 标记对象](#4.6 gcDrain - 标记对象)
- [4.7 shade - 标记对象](#4.7 shade - 标记对象)
- [4.8 gcMarkDone - 标记完成检查](#4.8 gcMarkDone - 标记完成检查)
- [4.9 gcMarkTermination - 标记终止](#4.9 gcMarkTermination - 标记终止)
- [4.10 mspan.sweep - 清扫 span](#4.10 mspan.sweep - 清扫 span)
- [5. 基于当前项目的内存与 GC 专项复盘](#5. 基于当前项目的内存与 GC 专项复盘)
-
- [5.1 当前项目源码分析](#5.1 当前项目源码分析)
-
- [5.1.1 项目结构概览](#5.1.1 项目结构概览)
- [5.2 典型逃逸案例分析(基于 Go 源码)](#5.2 典型逃逸案例分析(基于 Go 源码))
- [5.3 堆对象热点分析](#5.3 堆对象热点分析)
-
- [热点1:编译器的 AST 节点分配](#热点1:编译器的 AST 节点分配)
- [热点2:runtime 的 span 分配](#热点2:runtime 的 span 分配)
- [5.4 内存隐患与可优化点](#5.4 内存隐患与可优化点)
-
- 隐患1:编译器内存峰值
- [隐患2:runtime 元数据内存开销](#隐患2:runtime 元数据内存开销)
- [5.5 实战优化建议](#5.5 实战优化建议)
-
- [优化1:使用 sync.Pool 重用对象](#优化1:使用 sync.Pool 重用对象)
- [优化2:使用对象 arena](#优化2:使用对象 arena)
- [优化3:调整 GOGC](#优化3:调整 GOGC)
- [6. 大厂面试高频真题 + 源码级标准答案](#6. 大厂面试高频真题 + 源码级标准答案)
-
- [6.1 内存分配面试题](#6.1 内存分配面试题)
-
- [题目1:Go 的内存分配器是如何工作的?](#题目1:Go 的内存分配器是如何工作的?)
- 题目2:什么是逃逸分析?如何判断对象是否逃逸?
- [题目3:span 是什么?spanClass 如何构成?](#题目3:span 是什么?spanClass 如何构成?)
- [6.2 GC 面试题](#6.2 GC 面试题)
-
- [题目4:Go 的 GC 是如何工作的?三色标记是什么?](#题目4:Go 的 GC 是如何工作的?三色标记是什么?)
- [题目5:写屏障是什么?Go 为什么需要写屏障?](#题目5:写屏障是什么?Go 为什么需要写屏障?)
- [题目6:STW 是什么时候发生的?持续多久?如何优化?](#题目6:STW 是什么时候发生的?持续多久?如何优化?)
- [题目7:GOGC 是如何工作的?如何调优?](#题目7:GOGC 是如何工作的?如何调优?)
- [题目8:如何观察和分析 Go 的内存和 GC 行为?](#题目8:如何观察和分析 Go 的内存和 GC 行为?)
- [6.3 实战场景面试题](#6.3 实战场景面试题)
-
- [题目9:内存泄漏如何排查?Go 有哪些常见内存泄漏?](#题目9:内存泄漏如何排查?Go 有哪些常见内存泄漏?)
- [题目10:什么是内存碎片?Go 如何处理内存碎片?](#题目10:什么是内存碎片?Go 如何处理内存碎片?)
- [7. 工程化优化总结与线上排查思路](#7. 工程化优化总结与线上排查思路)
-
- [7.1 编码优化建议](#7.1 编码优化建议)
- [7.2 GC 参数调优](#7.2 GC 参数调优)
-
- [调优1:GOGC 调整](#调优1:GOGC 调整)
- [调优2:GOMEMLIMIT 使用(Go 1.19+)](#调优2:GOMEMLIMIT 使用(Go 1.19+))
- [调优3:GOMAXPROCS 设置](#调优3:GOMAXPROCS 设置)
- [7.3 线上问题排查链路](#7.3 线上问题排查链路)
-
- 排查步骤1:初步观察
- [排查步骤2:pprof 采样](#排查步骤2:pprof 采样)
- 排查步骤3:深入分析
- [7.4 pprof 核心视图解读](#7.4 pprof 核心视图解读)
-
- [heap profile 视图](#heap profile 视图)
- [trace 视图](#trace 视图)
- [7.5 常见问题与解决方案速查](#7.5 常见问题与解决方案速查)
1. 核心基础与面试前置知识
1.1 内存布局基础
用户态与内核态内存
#mermaid-svg-vP0l8YWLvjrWesxX{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-vP0l8YWLvjrWesxX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vP0l8YWLvjrWesxX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vP0l8YWLvjrWesxX .error-icon{fill:#552222;}#mermaid-svg-vP0l8YWLvjrWesxX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vP0l8YWLvjrWesxX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vP0l8YWLvjrWesxX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vP0l8YWLvjrWesxX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vP0l8YWLvjrWesxX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vP0l8YWLvjrWesxX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vP0l8YWLvjrWesxX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vP0l8YWLvjrWesxX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vP0l8YWLvjrWesxX .marker.cross{stroke:#333333;}#mermaid-svg-vP0l8YWLvjrWesxX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vP0l8YWLvjrWesxX p{margin:0;}#mermaid-svg-vP0l8YWLvjrWesxX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vP0l8YWLvjrWesxX .cluster-label text{fill:#333;}#mermaid-svg-vP0l8YWLvjrWesxX .cluster-label span{color:#333;}#mermaid-svg-vP0l8YWLvjrWesxX .cluster-label span p{background-color:transparent;}#mermaid-svg-vP0l8YWLvjrWesxX .label text,#mermaid-svg-vP0l8YWLvjrWesxX span{fill:#333;color:#333;}#mermaid-svg-vP0l8YWLvjrWesxX .node rect,#mermaid-svg-vP0l8YWLvjrWesxX .node circle,#mermaid-svg-vP0l8YWLvjrWesxX .node ellipse,#mermaid-svg-vP0l8YWLvjrWesxX .node polygon,#mermaid-svg-vP0l8YWLvjrWesxX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vP0l8YWLvjrWesxX .rough-node .label text,#mermaid-svg-vP0l8YWLvjrWesxX .node .label text,#mermaid-svg-vP0l8YWLvjrWesxX .image-shape .label,#mermaid-svg-vP0l8YWLvjrWesxX .icon-shape .label{text-anchor:middle;}#mermaid-svg-vP0l8YWLvjrWesxX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vP0l8YWLvjrWesxX .rough-node .label,#mermaid-svg-vP0l8YWLvjrWesxX .node .label,#mermaid-svg-vP0l8YWLvjrWesxX .image-shape .label,#mermaid-svg-vP0l8YWLvjrWesxX .icon-shape .label{text-align:center;}#mermaid-svg-vP0l8YWLvjrWesxX .node.clickable{cursor:pointer;}#mermaid-svg-vP0l8YWLvjrWesxX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vP0l8YWLvjrWesxX .arrowheadPath{fill:#333333;}#mermaid-svg-vP0l8YWLvjrWesxX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vP0l8YWLvjrWesxX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vP0l8YWLvjrWesxX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vP0l8YWLvjrWesxX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vP0l8YWLvjrWesxX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vP0l8YWLvjrWesxX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vP0l8YWLvjrWesxX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vP0l8YWLvjrWesxX .cluster text{fill:#333;}#mermaid-svg-vP0l8YWLvjrWesxX .cluster span{color:#333;}#mermaid-svg-vP0l8YWLvjrWesxX 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-vP0l8YWLvjrWesxX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vP0l8YWLvjrWesxX rect.text{fill:none;stroke-width:0;}#mermaid-svg-vP0l8YWLvjrWesxX .icon-shape,#mermaid-svg-vP0l8YWLvjrWesxX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vP0l8YWLvjrWesxX .icon-shape p,#mermaid-svg-vP0l8YWLvjrWesxX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vP0l8YWLvjrWesxX .icon-shape .label rect,#mermaid-svg-vP0l8YWLvjrWesxX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vP0l8YWLvjrWesxX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vP0l8YWLvjrWesxX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vP0l8YWLvjrWesxX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 虚拟地址空间
用户态空间
栈区
(向下增长)
堆区
(向上增长)
BSS段
(未初始化数据)
数据段
(已初始化数据)
代码段
(只读)
内核态空间
内核代码/数据
(高地址)
关键要点:
- 用户态:应用程序运行的空间,只能访问自己的内存
- 内核态:操作系统内核运行的空间,可以访问所有内存
- 系统调用:用户态与内核态切换的桥梁,有开销
栈内存与堆内存本质区别
| 特性 | 栈 | 堆 |
|---|---|---|
| 分配方式 | 编译器自动分配释放 | 开发者手动分配或 GC 管理 |
| 分配速度 | 极快(仅移动栈指针) | 较慢(需要查找可用空间) |
| 空间大小 | 有限( goroutine 栈初始 2KB) | 较大(受限于系统内存) |
| 生命周期 | 随函数调用结束而释放 | 随 GC 周期回收 |
| 内存碎片 | 无(连续分配) | 可能有(离散分配) |
| 访问方式 | 直接访问 | 通过指针间接访问 |
| 线程安全 | 每个 goroutine 独立栈 | 需要并发控制 |
1.2 对象生命周期
#mermaid-svg-SvTwaVRt5RLVin7Y{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-SvTwaVRt5RLVin7Y .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SvTwaVRt5RLVin7Y .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SvTwaVRt5RLVin7Y .error-icon{fill:#552222;}#mermaid-svg-SvTwaVRt5RLVin7Y .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SvTwaVRt5RLVin7Y .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SvTwaVRt5RLVin7Y .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SvTwaVRt5RLVin7Y .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SvTwaVRt5RLVin7Y .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SvTwaVRt5RLVin7Y .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SvTwaVRt5RLVin7Y .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SvTwaVRt5RLVin7Y .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SvTwaVRt5RLVin7Y .marker.cross{stroke:#333333;}#mermaid-svg-SvTwaVRt5RLVin7Y svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SvTwaVRt5RLVin7Y p{margin:0;}#mermaid-svg-SvTwaVRt5RLVin7Y defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-SvTwaVRt5RLVin7Y g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-SvTwaVRt5RLVin7Y g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-SvTwaVRt5RLVin7Y g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-SvTwaVRt5RLVin7Y g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-SvTwaVRt5RLVin7Y g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-SvTwaVRt5RLVin7Y .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-SvTwaVRt5RLVin7Y .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-SvTwaVRt5RLVin7Y .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-SvTwaVRt5RLVin7Y .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-SvTwaVRt5RLVin7Y .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-SvTwaVRt5RLVin7Y .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-SvTwaVRt5RLVin7Y .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-SvTwaVRt5RLVin7Y .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SvTwaVRt5RLVin7Y .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SvTwaVRt5RLVin7Y .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SvTwaVRt5RLVin7Y .edgeLabel .label text{fill:#333;}#mermaid-svg-SvTwaVRt5RLVin7Y .label div .edgeLabel{color:#333;}#mermaid-svg-SvTwaVRt5RLVin7Y .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-SvTwaVRt5RLVin7Y .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-SvTwaVRt5RLVin7Y .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-SvTwaVRt5RLVin7Y .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-SvTwaVRt5RLVin7Y .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-SvTwaVRt5RLVin7Y .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SvTwaVRt5RLVin7Y .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SvTwaVRt5RLVin7Y #statediagram-barbEnd{fill:#333333;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SvTwaVRt5RLVin7Y .cluster-label,#mermaid-svg-SvTwaVRt5RLVin7Y .nodeLabel{color:#131300;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-SvTwaVRt5RLVin7Y .note-edge{stroke-dasharray:5;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-note text{fill:black;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram-note .nodeLabel{color:black;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagram .edgeLabel{color:red;}#mermaid-svg-SvTwaVRt5RLVin7Y #dependencyStart,#mermaid-svg-SvTwaVRt5RLVin7Y #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-SvTwaVRt5RLVin7Y .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SvTwaVRt5RLVin7Y :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 源码编译
确定分配位置
未逃逸
已逃逸
函数执行
函数返回
指针引用
可达对象
不可达对象
归还堆
编译阶段
逃逸分析
栈分配
堆分配
使用中
栈释放
GC标记
GC清扫
内存释放
1.3 编译器逃逸分析作用
逃逸分析定义:编译器在编译阶段分析变量的作用域和生命周期,确定其应该分配在栈上还是堆上。
逃逸场景:
- 函数返回局部变量指针
- 变量被发送到通道
- 变量被闭包捕获
- 变量类型不确定(如
interface{}) - 变量过大超过栈限制
逃逸分析源码位置 :src/cmd/compile/internal/escape/escape.go
1.4 GC 的设计目标与约束
Go GC 的核心设计目标:
- 低延迟:STW 时间尽可能短
- 高吞吐量:GC 占用的 CPU 时间尽可能少
- 自动内存管理:开发者无需手动管理内存
- 可伸缩:支持多核心和大内存场景
- 简单性:算法相对简单,易于维护
设计约束:
- 必须是并发的(不能长时间 STW)
- 必须是精确的(知道每个指针的位置)
- 不能是移动的(不压缩堆,避免写屏障复杂度过高)
1.5 Go 与 Java GC 的设计差异
| 特性 | Go GC | Java GC |
|---|---|---|
| 算法 | 三色标记 + 写屏障 | 多种(分代、G1、ZGC等) |
| 分代 | 无分代 | 分代(年轻代/老年代) |
| 压缩 | 不压缩 | 多数实现会压缩 |
| STW | 通常 < 1ms | 几十ms 到 几秒 |
| 调优参数 | GOGC, GOMEMLIMIT |
-Xms, -Xmx, -XX:+UseG1GC等 |
| 内存分配 | TLAB 类似(mcache) | TLAB + 老年代分配 |
| 写屏障 | Dijkstra-style | SATB、Card Table 等 |
1.6 大厂面试基础易错点
易错点1:认为"new 分配在堆,变量声明分配在栈"
- 错误!分配位置由逃逸分析决定,与语法无关
易错点2:认为"GC 频率越高越好"
- 错误!GC 频率过高会导致 CPU 占用过高
- 应根据实际情况调整
GOGC
易错点3:认为"栈内存不会有内存泄漏"
- 错误!goroutine 泄漏会导致栈内存无法释放
易错点4:认为"所有指针都在堆上"
- 错误!指针本身可能在栈上,指向的对象可能在堆上
2. Go 内存分配完整底层原理(重点深挖)
2.1 内存分配架构总览
Go 的内存分配器采用了 TCMalloc 类似的设计,核心思想是多级缓存以减少锁竞争。
#mermaid-svg-txblaeZAY22NgqFX{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-txblaeZAY22NgqFX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-txblaeZAY22NgqFX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-txblaeZAY22NgqFX .error-icon{fill:#552222;}#mermaid-svg-txblaeZAY22NgqFX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-txblaeZAY22NgqFX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-txblaeZAY22NgqFX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-txblaeZAY22NgqFX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-txblaeZAY22NgqFX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-txblaeZAY22NgqFX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-txblaeZAY22NgqFX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-txblaeZAY22NgqFX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-txblaeZAY22NgqFX .marker.cross{stroke:#333333;}#mermaid-svg-txblaeZAY22NgqFX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-txblaeZAY22NgqFX p{margin:0;}#mermaid-svg-txblaeZAY22NgqFX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-txblaeZAY22NgqFX .cluster-label text{fill:#333;}#mermaid-svg-txblaeZAY22NgqFX .cluster-label span{color:#333;}#mermaid-svg-txblaeZAY22NgqFX .cluster-label span p{background-color:transparent;}#mermaid-svg-txblaeZAY22NgqFX .label text,#mermaid-svg-txblaeZAY22NgqFX span{fill:#333;color:#333;}#mermaid-svg-txblaeZAY22NgqFX .node rect,#mermaid-svg-txblaeZAY22NgqFX .node circle,#mermaid-svg-txblaeZAY22NgqFX .node ellipse,#mermaid-svg-txblaeZAY22NgqFX .node polygon,#mermaid-svg-txblaeZAY22NgqFX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-txblaeZAY22NgqFX .rough-node .label text,#mermaid-svg-txblaeZAY22NgqFX .node .label text,#mermaid-svg-txblaeZAY22NgqFX .image-shape .label,#mermaid-svg-txblaeZAY22NgqFX .icon-shape .label{text-anchor:middle;}#mermaid-svg-txblaeZAY22NgqFX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-txblaeZAY22NgqFX .rough-node .label,#mermaid-svg-txblaeZAY22NgqFX .node .label,#mermaid-svg-txblaeZAY22NgqFX .image-shape .label,#mermaid-svg-txblaeZAY22NgqFX .icon-shape .label{text-align:center;}#mermaid-svg-txblaeZAY22NgqFX .node.clickable{cursor:pointer;}#mermaid-svg-txblaeZAY22NgqFX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-txblaeZAY22NgqFX .arrowheadPath{fill:#333333;}#mermaid-svg-txblaeZAY22NgqFX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-txblaeZAY22NgqFX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-txblaeZAY22NgqFX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-txblaeZAY22NgqFX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-txblaeZAY22NgqFX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-txblaeZAY22NgqFX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-txblaeZAY22NgqFX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-txblaeZAY22NgqFX .cluster text{fill:#333;}#mermaid-svg-txblaeZAY22NgqFX .cluster span{color:#333;}#mermaid-svg-txblaeZAY22NgqFX 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-txblaeZAY22NgqFX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-txblaeZAY22NgqFX rect.text{fill:none;stroke-width:0;}#mermaid-svg-txblaeZAY22NgqFX .icon-shape,#mermaid-svg-txblaeZAY22NgqFX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-txblaeZAY22NgqFX .icon-shape p,#mermaid-svg-txblaeZAY22NgqFX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-txblaeZAY22NgqFX .icon-shape .label rect,#mermaid-svg-txblaeZAY22NgqFX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-txblaeZAY22NgqFX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-txblaeZAY22NgqFX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-txblaeZAY22NgqFX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} OS 层
Heap 层
Central 层
Per-P 缓存层
CPU层面
P (Logical Processor)
P (Logical Processor)
mcache
(无锁)
mcache
(无锁)
mcentral
(size class 1)
mcentral
(size class 2)
mcentral
(size class N)
mheap
(全局锁)
heapArena
(64MB 块)
操作系统
虚拟内存
2.2 M/P/G 与内存调度的关系
源码位置 :src/runtime/runtime2.go
#mermaid-svg-yDACxbliKFQ6evAv{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-yDACxbliKFQ6evAv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yDACxbliKFQ6evAv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yDACxbliKFQ6evAv .error-icon{fill:#552222;}#mermaid-svg-yDACxbliKFQ6evAv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yDACxbliKFQ6evAv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yDACxbliKFQ6evAv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yDACxbliKFQ6evAv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yDACxbliKFQ6evAv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yDACxbliKFQ6evAv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yDACxbliKFQ6evAv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yDACxbliKFQ6evAv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yDACxbliKFQ6evAv .marker.cross{stroke:#333333;}#mermaid-svg-yDACxbliKFQ6evAv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yDACxbliKFQ6evAv p{margin:0;}#mermaid-svg-yDACxbliKFQ6evAv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yDACxbliKFQ6evAv .cluster-label text{fill:#333;}#mermaid-svg-yDACxbliKFQ6evAv .cluster-label span{color:#333;}#mermaid-svg-yDACxbliKFQ6evAv .cluster-label span p{background-color:transparent;}#mermaid-svg-yDACxbliKFQ6evAv .label text,#mermaid-svg-yDACxbliKFQ6evAv span{fill:#333;color:#333;}#mermaid-svg-yDACxbliKFQ6evAv .node rect,#mermaid-svg-yDACxbliKFQ6evAv .node circle,#mermaid-svg-yDACxbliKFQ6evAv .node ellipse,#mermaid-svg-yDACxbliKFQ6evAv .node polygon,#mermaid-svg-yDACxbliKFQ6evAv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yDACxbliKFQ6evAv .rough-node .label text,#mermaid-svg-yDACxbliKFQ6evAv .node .label text,#mermaid-svg-yDACxbliKFQ6evAv .image-shape .label,#mermaid-svg-yDACxbliKFQ6evAv .icon-shape .label{text-anchor:middle;}#mermaid-svg-yDACxbliKFQ6evAv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yDACxbliKFQ6evAv .rough-node .label,#mermaid-svg-yDACxbliKFQ6evAv .node .label,#mermaid-svg-yDACxbliKFQ6evAv .image-shape .label,#mermaid-svg-yDACxbliKFQ6evAv .icon-shape .label{text-align:center;}#mermaid-svg-yDACxbliKFQ6evAv .node.clickable{cursor:pointer;}#mermaid-svg-yDACxbliKFQ6evAv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yDACxbliKFQ6evAv .arrowheadPath{fill:#333333;}#mermaid-svg-yDACxbliKFQ6evAv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yDACxbliKFQ6evAv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yDACxbliKFQ6evAv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yDACxbliKFQ6evAv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yDACxbliKFQ6evAv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yDACxbliKFQ6evAv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yDACxbliKFQ6evAv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yDACxbliKFQ6evAv .cluster text{fill:#333;}#mermaid-svg-yDACxbliKFQ6evAv .cluster span{color:#333;}#mermaid-svg-yDACxbliKFQ6evAv 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-yDACxbliKFQ6evAv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yDACxbliKFQ6evAv rect.text{fill:none;stroke-width:0;}#mermaid-svg-yDACxbliKFQ6evAv .icon-shape,#mermaid-svg-yDACxbliKFQ6evAv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yDACxbliKFQ6evAv .icon-shape p,#mermaid-svg-yDACxbliKFQ6evAv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yDACxbliKFQ6evAv .icon-shape .label rect,#mermaid-svg-yDACxbliKFQ6evAv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yDACxbliKFQ6evAv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yDACxbliKFQ6evAv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yDACxbliKFQ6evAv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} G (Goroutine)
P (Logical Processor)
M (Machine Thread)
M1
操作系统线程
M2
操作系统线程
P1
本地运行队列
mcache
P2
本地运行队列
mcache
G1
G2
G3
G4
关键数据结构:
- M:代表操作系统线程,真正执行代码的实体
- P:代表逻辑处理器,包含调度上下文和 mcache
- G:代表 goroutine,包含栈和执行状态
与内存分配的关系:
- 每个 P 有自己的 mcache
- G 在 M 上执行,通过 P 的 mcache 分配内存
- 无锁分配:同一 P 上的 G 分配内存无需加锁
2.3 mcache 层详解
源码位置 :src/runtime/mcache.go
#mermaid-svg-c4hIoealHmb8ZRyb{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-c4hIoealHmb8ZRyb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-c4hIoealHmb8ZRyb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-c4hIoealHmb8ZRyb .error-icon{fill:#552222;}#mermaid-svg-c4hIoealHmb8ZRyb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-c4hIoealHmb8ZRyb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-c4hIoealHmb8ZRyb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-c4hIoealHmb8ZRyb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-c4hIoealHmb8ZRyb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-c4hIoealHmb8ZRyb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-c4hIoealHmb8ZRyb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-c4hIoealHmb8ZRyb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-c4hIoealHmb8ZRyb .marker.cross{stroke:#333333;}#mermaid-svg-c4hIoealHmb8ZRyb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-c4hIoealHmb8ZRyb p{margin:0;}#mermaid-svg-c4hIoealHmb8ZRyb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-c4hIoealHmb8ZRyb .cluster-label text{fill:#333;}#mermaid-svg-c4hIoealHmb8ZRyb .cluster-label span{color:#333;}#mermaid-svg-c4hIoealHmb8ZRyb .cluster-label span p{background-color:transparent;}#mermaid-svg-c4hIoealHmb8ZRyb .label text,#mermaid-svg-c4hIoealHmb8ZRyb span{fill:#333;color:#333;}#mermaid-svg-c4hIoealHmb8ZRyb .node rect,#mermaid-svg-c4hIoealHmb8ZRyb .node circle,#mermaid-svg-c4hIoealHmb8ZRyb .node ellipse,#mermaid-svg-c4hIoealHmb8ZRyb .node polygon,#mermaid-svg-c4hIoealHmb8ZRyb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-c4hIoealHmb8ZRyb .rough-node .label text,#mermaid-svg-c4hIoealHmb8ZRyb .node .label text,#mermaid-svg-c4hIoealHmb8ZRyb .image-shape .label,#mermaid-svg-c4hIoealHmb8ZRyb .icon-shape .label{text-anchor:middle;}#mermaid-svg-c4hIoealHmb8ZRyb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-c4hIoealHmb8ZRyb .rough-node .label,#mermaid-svg-c4hIoealHmb8ZRyb .node .label,#mermaid-svg-c4hIoealHmb8ZRyb .image-shape .label,#mermaid-svg-c4hIoealHmb8ZRyb .icon-shape .label{text-align:center;}#mermaid-svg-c4hIoealHmb8ZRyb .node.clickable{cursor:pointer;}#mermaid-svg-c4hIoealHmb8ZRyb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-c4hIoealHmb8ZRyb .arrowheadPath{fill:#333333;}#mermaid-svg-c4hIoealHmb8ZRyb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-c4hIoealHmb8ZRyb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-c4hIoealHmb8ZRyb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-c4hIoealHmb8ZRyb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-c4hIoealHmb8ZRyb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-c4hIoealHmb8ZRyb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-c4hIoealHmb8ZRyb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-c4hIoealHmb8ZRyb .cluster text{fill:#333;}#mermaid-svg-c4hIoealHmb8ZRyb .cluster span{color:#333;}#mermaid-svg-c4hIoealHmb8ZRyb 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-c4hIoealHmb8ZRyb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-c4hIoealHmb8ZRyb rect.text{fill:none;stroke-width:0;}#mermaid-svg-c4hIoealHmb8ZRyb .icon-shape,#mermaid-svg-c4hIoealHmb8ZRyb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-c4hIoealHmb8ZRyb .icon-shape p,#mermaid-svg-c4hIoealHmb8ZRyb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-c4hIoealHmb8ZRyb .icon-shape .label rect,#mermaid-svg-c4hIoealHmb8ZRyb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-c4hIoealHmb8ZRyb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-c4hIoealHmb8ZRyb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-c4hIoealHmb8ZRyb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} spanClass
mcache 结构
scanAlloc
已分配扫描字节数
tiny
微对象块指针
tinyoffset
微对象偏移
alloc68
span 数组
reusableNoscan68
重用对象链表
stackcache
栈缓存
flushGen
刷新世代
size class 0
noscan
size class 0
scan
size class 1
noscan
size class 67
scan
mcache 核心结构(来自源码):
go
type mcache struct {
nextSample int64 // 下次堆采样触发点
scanAlloc uintptr // 已分配可扫描堆字节数
// 微对象分配器(< 16B,无指针)
tiny uintptr
tinyoffset uintptr
tinyAllocs uintptr
// 按 spanClass 索引的 span 数组
alloc [numSpanClasses]*mspan
// 重用对象链表(noscan)
reusableNoscan [numSpanClasses]gclinkptr
stackcache [_NumStackOrders]stackfreelist
flushGen atomic.Uint32
}
mcache 工作流程:
mheap mcentral mcache Goroutine mheap mcentral mcache Goroutine #mermaid-svg-GDs2OBltv8zFqiLF{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-GDs2OBltv8zFqiLF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GDs2OBltv8zFqiLF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GDs2OBltv8zFqiLF .error-icon{fill:#552222;}#mermaid-svg-GDs2OBltv8zFqiLF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GDs2OBltv8zFqiLF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GDs2OBltv8zFqiLF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GDs2OBltv8zFqiLF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GDs2OBltv8zFqiLF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GDs2OBltv8zFqiLF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GDs2OBltv8zFqiLF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GDs2OBltv8zFqiLF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GDs2OBltv8zFqiLF .marker.cross{stroke:#333333;}#mermaid-svg-GDs2OBltv8zFqiLF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GDs2OBltv8zFqiLF p{margin:0;}#mermaid-svg-GDs2OBltv8zFqiLF .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GDs2OBltv8zFqiLF text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-GDs2OBltv8zFqiLF .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-GDs2OBltv8zFqiLF .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-GDs2OBltv8zFqiLF .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-GDs2OBltv8zFqiLF .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-GDs2OBltv8zFqiLF #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-GDs2OBltv8zFqiLF .sequenceNumber{fill:white;}#mermaid-svg-GDs2OBltv8zFqiLF #sequencenumber{fill:#333;}#mermaid-svg-GDs2OBltv8zFqiLF #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-GDs2OBltv8zFqiLF .messageText{fill:#333;stroke:none;}#mermaid-svg-GDs2OBltv8zFqiLF .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GDs2OBltv8zFqiLF .labelText,#mermaid-svg-GDs2OBltv8zFqiLF .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-GDs2OBltv8zFqiLF .loopText,#mermaid-svg-GDs2OBltv8zFqiLF .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-GDs2OBltv8zFqiLF .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-GDs2OBltv8zFqiLF .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-GDs2OBltv8zFqiLF .noteText,#mermaid-svg-GDs2OBltv8zFqiLF .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-GDs2OBltv8zFqiLF .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GDs2OBltv8zFqiLF .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GDs2OBltv8zFqiLF .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GDs2OBltv8zFqiLF .actorPopupMenu{position:absolute;}#mermaid-svg-GDs2OBltv8zFqiLF .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-GDs2OBltv8zFqiLF .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GDs2OBltv8zFqiLF .actor-man circle,#mermaid-svg-GDs2OBltv8zFqiLF line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-GDs2OBltv8zFqiLF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt central 有 span central 无 span alt 有空闲 span 无空闲 span 分配 small object 从 allocspc 分配 refill(spc) 查找可用 span 返回 span grow() 从堆分配新 span 返回 span 返回 span 存入 allocspc 返回对象指针
2.4 mcentral 层详解
源码位置 :src/runtime/mcentral.go
#mermaid-svg-zdVvbhyl75PMalyz{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-zdVvbhyl75PMalyz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zdVvbhyl75PMalyz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zdVvbhyl75PMalyz .error-icon{fill:#552222;}#mermaid-svg-zdVvbhyl75PMalyz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zdVvbhyl75PMalyz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zdVvbhyl75PMalyz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zdVvbhyl75PMalyz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zdVvbhyl75PMalyz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zdVvbhyl75PMalyz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zdVvbhyl75PMalyz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zdVvbhyl75PMalyz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zdVvbhyl75PMalyz .marker.cross{stroke:#333333;}#mermaid-svg-zdVvbhyl75PMalyz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zdVvbhyl75PMalyz p{margin:0;}#mermaid-svg-zdVvbhyl75PMalyz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zdVvbhyl75PMalyz .cluster-label text{fill:#333;}#mermaid-svg-zdVvbhyl75PMalyz .cluster-label span{color:#333;}#mermaid-svg-zdVvbhyl75PMalyz .cluster-label span p{background-color:transparent;}#mermaid-svg-zdVvbhyl75PMalyz .label text,#mermaid-svg-zdVvbhyl75PMalyz span{fill:#333;color:#333;}#mermaid-svg-zdVvbhyl75PMalyz .node rect,#mermaid-svg-zdVvbhyl75PMalyz .node circle,#mermaid-svg-zdVvbhyl75PMalyz .node ellipse,#mermaid-svg-zdVvbhyl75PMalyz .node polygon,#mermaid-svg-zdVvbhyl75PMalyz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zdVvbhyl75PMalyz .rough-node .label text,#mermaid-svg-zdVvbhyl75PMalyz .node .label text,#mermaid-svg-zdVvbhyl75PMalyz .image-shape .label,#mermaid-svg-zdVvbhyl75PMalyz .icon-shape .label{text-anchor:middle;}#mermaid-svg-zdVvbhyl75PMalyz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zdVvbhyl75PMalyz .rough-node .label,#mermaid-svg-zdVvbhyl75PMalyz .node .label,#mermaid-svg-zdVvbhyl75PMalyz .image-shape .label,#mermaid-svg-zdVvbhyl75PMalyz .icon-shape .label{text-align:center;}#mermaid-svg-zdVvbhyl75PMalyz .node.clickable{cursor:pointer;}#mermaid-svg-zdVvbhyl75PMalyz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zdVvbhyl75PMalyz .arrowheadPath{fill:#333333;}#mermaid-svg-zdVvbhyl75PMalyz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zdVvbhyl75PMalyz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zdVvbhyl75PMalyz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zdVvbhyl75PMalyz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zdVvbhyl75PMalyz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zdVvbhyl75PMalyz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zdVvbhyl75PMalyz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zdVvbhyl75PMalyz .cluster text{fill:#333;}#mermaid-svg-zdVvbhyl75PMalyz .cluster span{color:#333;}#mermaid-svg-zdVvbhyl75PMalyz 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-zdVvbhyl75PMalyz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zdVvbhyl75PMalyz rect.text{fill:none;stroke-width:0;}#mermaid-svg-zdVvbhyl75PMalyz .icon-shape,#mermaid-svg-zdVvbhyl75PMalyz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zdVvbhyl75PMalyz .icon-shape p,#mermaid-svg-zdVvbhyl75PMalyz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zdVvbhyl75PMalyz .icon-shape .label rect,#mermaid-svg-zdVvbhyl75PMalyz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zdVvbhyl75PMalyz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zdVvbhyl75PMalyz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zdVvbhyl75PMalyz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} sweepgen 机制
mcentral 结构
spanClass
大小类
partial2spanSet
部分空闲 span
full2spanSet
满 span
partialsweepgen/2%2
已清扫
partial1-sweepgen/2%2
未清扫
mcentral 核心结构:
go
type mcentral struct {
spanclass spanClass
// partial 和 full 各有两个 spanSet
// 用于区分已清扫和未清扫的 span
partial [2]spanSet // 有空闲对象的 span
full [2]spanSet // 无空闲对象的 span
}
cacheSpan 方法流程 (来自 mcentral.go):
#mermaid-svg-DysXcyvdAGMIm1Ak{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-DysXcyvdAGMIm1Ak .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DysXcyvdAGMIm1Ak .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DysXcyvdAGMIm1Ak .error-icon{fill:#552222;}#mermaid-svg-DysXcyvdAGMIm1Ak .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DysXcyvdAGMIm1Ak .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DysXcyvdAGMIm1Ak .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DysXcyvdAGMIm1Ak .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DysXcyvdAGMIm1Ak .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DysXcyvdAGMIm1Ak .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DysXcyvdAGMIm1Ak .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DysXcyvdAGMIm1Ak .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DysXcyvdAGMIm1Ak .marker.cross{stroke:#333333;}#mermaid-svg-DysXcyvdAGMIm1Ak svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DysXcyvdAGMIm1Ak p{margin:0;}#mermaid-svg-DysXcyvdAGMIm1Ak .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DysXcyvdAGMIm1Ak .cluster-label text{fill:#333;}#mermaid-svg-DysXcyvdAGMIm1Ak .cluster-label span{color:#333;}#mermaid-svg-DysXcyvdAGMIm1Ak .cluster-label span p{background-color:transparent;}#mermaid-svg-DysXcyvdAGMIm1Ak .label text,#mermaid-svg-DysXcyvdAGMIm1Ak span{fill:#333;color:#333;}#mermaid-svg-DysXcyvdAGMIm1Ak .node rect,#mermaid-svg-DysXcyvdAGMIm1Ak .node circle,#mermaid-svg-DysXcyvdAGMIm1Ak .node ellipse,#mermaid-svg-DysXcyvdAGMIm1Ak .node polygon,#mermaid-svg-DysXcyvdAGMIm1Ak .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DysXcyvdAGMIm1Ak .rough-node .label text,#mermaid-svg-DysXcyvdAGMIm1Ak .node .label text,#mermaid-svg-DysXcyvdAGMIm1Ak .image-shape .label,#mermaid-svg-DysXcyvdAGMIm1Ak .icon-shape .label{text-anchor:middle;}#mermaid-svg-DysXcyvdAGMIm1Ak .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DysXcyvdAGMIm1Ak .rough-node .label,#mermaid-svg-DysXcyvdAGMIm1Ak .node .label,#mermaid-svg-DysXcyvdAGMIm1Ak .image-shape .label,#mermaid-svg-DysXcyvdAGMIm1Ak .icon-shape .label{text-align:center;}#mermaid-svg-DysXcyvdAGMIm1Ak .node.clickable{cursor:pointer;}#mermaid-svg-DysXcyvdAGMIm1Ak .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DysXcyvdAGMIm1Ak .arrowheadPath{fill:#333333;}#mermaid-svg-DysXcyvdAGMIm1Ak .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DysXcyvdAGMIm1Ak .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DysXcyvdAGMIm1Ak .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DysXcyvdAGMIm1Ak .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DysXcyvdAGMIm1Ak .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DysXcyvdAGMIm1Ak .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DysXcyvdAGMIm1Ak .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DysXcyvdAGMIm1Ak .cluster text{fill:#333;}#mermaid-svg-DysXcyvdAGMIm1Ak .cluster span{color:#333;}#mermaid-svg-DysXcyvdAGMIm1Ak 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-DysXcyvdAGMIm1Ak .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DysXcyvdAGMIm1Ak rect.text{fill:none;stroke-width:0;}#mermaid-svg-DysXcyvdAGMIm1Ak .icon-shape,#mermaid-svg-DysXcyvdAGMIm1Ak .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DysXcyvdAGMIm1Ak .icon-shape p,#mermaid-svg-DysXcyvdAGMIm1Ak .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DysXcyvdAGMIm1Ak .icon-shape .label rect,#mermaid-svg-DysXcyvdAGMIm1Ak .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DysXcyvdAGMIm1Ak .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DysXcyvdAGMIm1Ak .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DysXcyvdAGMIm1Ak :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
是
否
否
是
是
否
否
开始 cacheSpan
partialSwept
有 span?
pop 一个 span
返回 span
获取 sweepLocker
尝试 partialUnswept
spanBudget = 100
找到 span?
清扫 span
有空闲空间?
结束 sweep
push 到 fullSwept
继续尝试
尝试 fullUnswept
找到 span?
清扫 span
有空闲空间?
结束 sweep
push 到 fullSwept
调用 grow
从 mheap 分配新 span
2.5 mspan 结构详解
源码位置 :src/runtime/mheap.go (mspan 定义)
#mermaid-svg-EnEyY7iSwONuA08l{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-EnEyY7iSwONuA08l .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EnEyY7iSwONuA08l .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EnEyY7iSwONuA08l .error-icon{fill:#552222;}#mermaid-svg-EnEyY7iSwONuA08l .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EnEyY7iSwONuA08l .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EnEyY7iSwONuA08l .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EnEyY7iSwONuA08l .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EnEyY7iSwONuA08l .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EnEyY7iSwONuA08l .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EnEyY7iSwONuA08l .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EnEyY7iSwONuA08l .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EnEyY7iSwONuA08l .marker.cross{stroke:#333333;}#mermaid-svg-EnEyY7iSwONuA08l svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EnEyY7iSwONuA08l p{margin:0;}#mermaid-svg-EnEyY7iSwONuA08l .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EnEyY7iSwONuA08l .cluster-label text{fill:#333;}#mermaid-svg-EnEyY7iSwONuA08l .cluster-label span{color:#333;}#mermaid-svg-EnEyY7iSwONuA08l .cluster-label span p{background-color:transparent;}#mermaid-svg-EnEyY7iSwONuA08l .label text,#mermaid-svg-EnEyY7iSwONuA08l span{fill:#333;color:#333;}#mermaid-svg-EnEyY7iSwONuA08l .node rect,#mermaid-svg-EnEyY7iSwONuA08l .node circle,#mermaid-svg-EnEyY7iSwONuA08l .node ellipse,#mermaid-svg-EnEyY7iSwONuA08l .node polygon,#mermaid-svg-EnEyY7iSwONuA08l .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EnEyY7iSwONuA08l .rough-node .label text,#mermaid-svg-EnEyY7iSwONuA08l .node .label text,#mermaid-svg-EnEyY7iSwONuA08l .image-shape .label,#mermaid-svg-EnEyY7iSwONuA08l .icon-shape .label{text-anchor:middle;}#mermaid-svg-EnEyY7iSwONuA08l .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EnEyY7iSwONuA08l .rough-node .label,#mermaid-svg-EnEyY7iSwONuA08l .node .label,#mermaid-svg-EnEyY7iSwONuA08l .image-shape .label,#mermaid-svg-EnEyY7iSwONuA08l .icon-shape .label{text-align:center;}#mermaid-svg-EnEyY7iSwONuA08l .node.clickable{cursor:pointer;}#mermaid-svg-EnEyY7iSwONuA08l .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EnEyY7iSwONuA08l .arrowheadPath{fill:#333333;}#mermaid-svg-EnEyY7iSwONuA08l .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EnEyY7iSwONuA08l .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EnEyY7iSwONuA08l .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EnEyY7iSwONuA08l .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EnEyY7iSwONuA08l .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EnEyY7iSwONuA08l .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EnEyY7iSwONuA08l .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EnEyY7iSwONuA08l .cluster text{fill:#333;}#mermaid-svg-EnEyY7iSwONuA08l .cluster span{color:#333;}#mermaid-svg-EnEyY7iSwONuA08l 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-EnEyY7iSwONuA08l .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EnEyY7iSwONuA08l rect.text{fill:none;stroke-width:0;}#mermaid-svg-EnEyY7iSwONuA08l .icon-shape,#mermaid-svg-EnEyY7iSwONuA08l .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EnEyY7iSwONuA08l .icon-shape p,#mermaid-svg-EnEyY7iSwONuA08l .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EnEyY7iSwONuA08l .icon-shape .label rect,#mermaid-svg-EnEyY7iSwONuA08l .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EnEyY7iSwONuA08l .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EnEyY7iSwONuA08l .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EnEyY7iSwONuA08l :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} mspan 核心字段
GC相关
sweepgen
清扫世代
allocCount
已分配计数
分配管理
freeindex
下一个空闲索引
nelems
对象总数
allocCache
分配缓存
allocBits
分配位图
gcmarkBits
GC标记位图
startAddr
起始地址
npages
页数
spanclass
大小类
mspan 核心结构:
go
type mspan struct {
next *mspan
prev *mspan
startAddr uintptr // span 起始地址
npages uintptr // span 包含的页数
freeindex uintptr // 下一个空闲对象索引
nelems uintptr // span 中对象总数
allocCache uint64 // allocBits 缓存
allocBits *gcBits // 分配位图
gcmarkBits *gcBits // GC标记位图
sweepgen uint32 // 清扫世代
allocCount uintptr // 已分配对象数
}
sweepgen 机制:
sweepgen == h->sweepgen - 2:需要清扫sweepgen == h->sweepgen - 1:正在清扫sweepgen == h->sweepgen:已清扫,可用sweepgen == h->sweepgen + 3:已缓存
2.6 mheap 与 heapArena 详解
源码位置 :src/runtime/mheap.go
#mermaid-svg-oahEUewXh0dPORnk{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-oahEUewXh0dPORnk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oahEUewXh0dPORnk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oahEUewXh0dPORnk .error-icon{fill:#552222;}#mermaid-svg-oahEUewXh0dPORnk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oahEUewXh0dPORnk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oahEUewXh0dPORnk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oahEUewXh0dPORnk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oahEUewXh0dPORnk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oahEUewXh0dPORnk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oahEUewXh0dPORnk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oahEUewXh0dPORnk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oahEUewXh0dPORnk .marker.cross{stroke:#333333;}#mermaid-svg-oahEUewXh0dPORnk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oahEUewXh0dPORnk p{margin:0;}#mermaid-svg-oahEUewXh0dPORnk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-oahEUewXh0dPORnk .cluster-label text{fill:#333;}#mermaid-svg-oahEUewXh0dPORnk .cluster-label span{color:#333;}#mermaid-svg-oahEUewXh0dPORnk .cluster-label span p{background-color:transparent;}#mermaid-svg-oahEUewXh0dPORnk .label text,#mermaid-svg-oahEUewXh0dPORnk span{fill:#333;color:#333;}#mermaid-svg-oahEUewXh0dPORnk .node rect,#mermaid-svg-oahEUewXh0dPORnk .node circle,#mermaid-svg-oahEUewXh0dPORnk .node ellipse,#mermaid-svg-oahEUewXh0dPORnk .node polygon,#mermaid-svg-oahEUewXh0dPORnk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oahEUewXh0dPORnk .rough-node .label text,#mermaid-svg-oahEUewXh0dPORnk .node .label text,#mermaid-svg-oahEUewXh0dPORnk .image-shape .label,#mermaid-svg-oahEUewXh0dPORnk .icon-shape .label{text-anchor:middle;}#mermaid-svg-oahEUewXh0dPORnk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oahEUewXh0dPORnk .rough-node .label,#mermaid-svg-oahEUewXh0dPORnk .node .label,#mermaid-svg-oahEUewXh0dPORnk .image-shape .label,#mermaid-svg-oahEUewXh0dPORnk .icon-shape .label{text-align:center;}#mermaid-svg-oahEUewXh0dPORnk .node.clickable{cursor:pointer;}#mermaid-svg-oahEUewXh0dPORnk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oahEUewXh0dPORnk .arrowheadPath{fill:#333333;}#mermaid-svg-oahEUewXh0dPORnk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oahEUewXh0dPORnk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oahEUewXh0dPORnk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oahEUewXh0dPORnk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oahEUewXh0dPORnk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oahEUewXh0dPORnk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oahEUewXh0dPORnk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oahEUewXh0dPORnk .cluster text{fill:#333;}#mermaid-svg-oahEUewXh0dPORnk .cluster span{color:#333;}#mermaid-svg-oahEUewXh0dPORnk 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-oahEUewXh0dPORnk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oahEUewXh0dPORnk rect.text{fill:none;stroke-width:0;}#mermaid-svg-oahEUewXh0dPORnk .icon-shape,#mermaid-svg-oahEUewXh0dPORnk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oahEUewXh0dPORnk .icon-shape p,#mermaid-svg-oahEUewXh0dPORnk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oahEUewXh0dPORnk .icon-shape .label rect,#mermaid-svg-oahEUewXh0dPORnk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oahEUewXh0dPORnk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oahEUewXh0dPORnk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oahEUewXh0dPORnk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} mheap 结构
heapArena 结构
spanspagesPerArena
span 映射
pageInUse
页使用位图
pageMarks
页标记位图
zeroedBase
已清零基址
pages
页分配器
sweepgen
清扫世代
allspans
所有 span
central68
mcentral 数组
spanalloc
span 分配器
arenas
heapArena 二维数组
heapArenas
已映射 arena 列表
heapArena
mcentral
mheap 核心结构:
go
type mheap struct {
lock mutex
pages pageAlloc // 页分配器
sweepgen uint32 // 清扫世代
allspans []*mspan // 所有 span
// 每个 size class 对应一个 mcentral
central [numSpanClasses]struct {
mcentral mcentral
pad [...]byte
}
// heapArena 映射
arenas [1 << arenaL1Bits]*[1 << arenaL2Bits]*heapArena
// ... 其他字段
}
type heapArena struct {
spans [pagesPerArena]*mspan
pageInUse [pagesPerArena / 8]uint8
pageMarks [pagesPerArena / 8]uint8
zeroedBase uintptr
}
2.7 大小分类(Size Classes)
源码位置 :src/runtime/sizeclasses.go(生成文件)
Go 预定义了 68 个大小类,每个大小类对应特定的对象大小范围。
| size class | bytes | objects/span |
|---|---|---|
| 0 | 8 B | 512 |
| 1 | 16 B | 256 |
| 2 | 32 B | 128 |
| 3 | 48 B | 85 |
| 4 | 64 B | 64 |
| ... | ... | ... |
| 66 | 32768 B | 1 |
| 67 | 65536 B | 1 |
大小类设计原则:
- 小对象有更多的大小类,减少内部碎片
- 最大的小对象是 32KB
- 超过 32KB 的对象直接从堆分配(大对象)
2.8 分级分配策略详解
2.8.1 微对象(Tiny Objects: 0 < size ≤ 16B,无指针)
源码位置 :src/runtime/malloc.go 中的 mallocgcTiny
#mermaid-svg-58OyO2PIyyxp2AZ5{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-58OyO2PIyyxp2AZ5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-58OyO2PIyyxp2AZ5 .error-icon{fill:#552222;}#mermaid-svg-58OyO2PIyyxp2AZ5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-58OyO2PIyyxp2AZ5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .marker.cross{stroke:#333333;}#mermaid-svg-58OyO2PIyyxp2AZ5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-58OyO2PIyyxp2AZ5 p{margin:0;}#mermaid-svg-58OyO2PIyyxp2AZ5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .cluster-label text{fill:#333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .cluster-label span{color:#333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .cluster-label span p{background-color:transparent;}#mermaid-svg-58OyO2PIyyxp2AZ5 .label text,#mermaid-svg-58OyO2PIyyxp2AZ5 span{fill:#333;color:#333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .node rect,#mermaid-svg-58OyO2PIyyxp2AZ5 .node circle,#mermaid-svg-58OyO2PIyyxp2AZ5 .node ellipse,#mermaid-svg-58OyO2PIyyxp2AZ5 .node polygon,#mermaid-svg-58OyO2PIyyxp2AZ5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-58OyO2PIyyxp2AZ5 .rough-node .label text,#mermaid-svg-58OyO2PIyyxp2AZ5 .node .label text,#mermaid-svg-58OyO2PIyyxp2AZ5 .image-shape .label,#mermaid-svg-58OyO2PIyyxp2AZ5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-58OyO2PIyyxp2AZ5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-58OyO2PIyyxp2AZ5 .rough-node .label,#mermaid-svg-58OyO2PIyyxp2AZ5 .node .label,#mermaid-svg-58OyO2PIyyxp2AZ5 .image-shape .label,#mermaid-svg-58OyO2PIyyxp2AZ5 .icon-shape .label{text-align:center;}#mermaid-svg-58OyO2PIyyxp2AZ5 .node.clickable{cursor:pointer;}#mermaid-svg-58OyO2PIyyxp2AZ5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .arrowheadPath{fill:#333333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-58OyO2PIyyxp2AZ5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-58OyO2PIyyxp2AZ5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-58OyO2PIyyxp2AZ5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-58OyO2PIyyxp2AZ5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-58OyO2PIyyxp2AZ5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-58OyO2PIyyxp2AZ5 .cluster text{fill:#333;}#mermaid-svg-58OyO2PIyyxp2AZ5 .cluster span{color:#333;}#mermaid-svg-58OyO2PIyyxp2AZ5 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-58OyO2PIyyxp2AZ5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-58OyO2PIyyxp2AZ5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-58OyO2PIyyxp2AZ5 .icon-shape,#mermaid-svg-58OyO2PIyyxp2AZ5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-58OyO2PIyyxp2AZ5 .icon-shape p,#mermaid-svg-58OyO2PIyyxp2AZ5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-58OyO2PIyyxp2AZ5 .icon-shape .label rect,#mermaid-svg-58OyO2PIyyxp2AZ5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-58OyO2PIyyxp2AZ5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-58OyO2PIyyxp2AZ5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-58OyO2PIyyxp2AZ5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
分配微对象
tiny
有空间?
从 tiny 块分配
tinyoffset += size
返回指针
reusableNoscan
有对象?
从链表取一个
更新链表头
从 mcache 分配
新 tiny 块
初始化 tiny
特点:
- 多个微对象可以打包在同一个 16B 的块中
- 零内存浪费(充分利用内存)
- 仅适用于 noscan 对象(无指针)
2.8.2 小对象(Small Objects: 16B < size ≤ 32KB)
#mermaid-svg-aVongYXOEB04JTgE{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-aVongYXOEB04JTgE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aVongYXOEB04JTgE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aVongYXOEB04JTgE .error-icon{fill:#552222;}#mermaid-svg-aVongYXOEB04JTgE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aVongYXOEB04JTgE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aVongYXOEB04JTgE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aVongYXOEB04JTgE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aVongYXOEB04JTgE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aVongYXOEB04JTgE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aVongYXOEB04JTgE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aVongYXOEB04JTgE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aVongYXOEB04JTgE .marker.cross{stroke:#333333;}#mermaid-svg-aVongYXOEB04JTgE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aVongYXOEB04JTgE p{margin:0;}#mermaid-svg-aVongYXOEB04JTgE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aVongYXOEB04JTgE .cluster-label text{fill:#333;}#mermaid-svg-aVongYXOEB04JTgE .cluster-label span{color:#333;}#mermaid-svg-aVongYXOEB04JTgE .cluster-label span p{background-color:transparent;}#mermaid-svg-aVongYXOEB04JTgE .label text,#mermaid-svg-aVongYXOEB04JTgE span{fill:#333;color:#333;}#mermaid-svg-aVongYXOEB04JTgE .node rect,#mermaid-svg-aVongYXOEB04JTgE .node circle,#mermaid-svg-aVongYXOEB04JTgE .node ellipse,#mermaid-svg-aVongYXOEB04JTgE .node polygon,#mermaid-svg-aVongYXOEB04JTgE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aVongYXOEB04JTgE .rough-node .label text,#mermaid-svg-aVongYXOEB04JTgE .node .label text,#mermaid-svg-aVongYXOEB04JTgE .image-shape .label,#mermaid-svg-aVongYXOEB04JTgE .icon-shape .label{text-anchor:middle;}#mermaid-svg-aVongYXOEB04JTgE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aVongYXOEB04JTgE .rough-node .label,#mermaid-svg-aVongYXOEB04JTgE .node .label,#mermaid-svg-aVongYXOEB04JTgE .image-shape .label,#mermaid-svg-aVongYXOEB04JTgE .icon-shape .label{text-align:center;}#mermaid-svg-aVongYXOEB04JTgE .node.clickable{cursor:pointer;}#mermaid-svg-aVongYXOEB04JTgE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aVongYXOEB04JTgE .arrowheadPath{fill:#333333;}#mermaid-svg-aVongYXOEB04JTgE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aVongYXOEB04JTgE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aVongYXOEB04JTgE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aVongYXOEB04JTgE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aVongYXOEB04JTgE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aVongYXOEB04JTgE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aVongYXOEB04JTgE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aVongYXOEB04JTgE .cluster text{fill:#333;}#mermaid-svg-aVongYXOEB04JTgE .cluster span{color:#333;}#mermaid-svg-aVongYXOEB04JTgE 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-aVongYXOEB04JTgE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aVongYXOEB04JTgE rect.text{fill:none;stroke-width:0;}#mermaid-svg-aVongYXOEB04JTgE .icon-shape,#mermaid-svg-aVongYXOEB04JTgE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aVongYXOEB04JTgE .icon-shape p,#mermaid-svg-aVongYXOEB04JTgE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aVongYXOEB04JTgE .icon-shape .label rect,#mermaid-svg-aVongYXOEB04JTgE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aVongYXOEB04JTgE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aVongYXOEB04JTgE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aVongYXOEB04JTgE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
是
否
分配小对象
计算 size class
noscan?
spanClass =
makeSpanClass(sc, true)
spanClass =
makeSpanClass(sc, false)
reusableNoscan
有对象?
快速重用
返回指针
从 allocspc 分配
span
有空间?
使用 allocCache
快速分配
调用 refill(spc)
从 mcentral 获取 span
2.8.3 大对象(Large Objects: size > 32KB)
#mermaid-svg-8hzSEce5QPjByS8w{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-8hzSEce5QPjByS8w .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8hzSEce5QPjByS8w .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8hzSEce5QPjByS8w .error-icon{fill:#552222;}#mermaid-svg-8hzSEce5QPjByS8w .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8hzSEce5QPjByS8w .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8hzSEce5QPjByS8w .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8hzSEce5QPjByS8w .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8hzSEce5QPjByS8w .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8hzSEce5QPjByS8w .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8hzSEce5QPjByS8w .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8hzSEce5QPjByS8w .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8hzSEce5QPjByS8w .marker.cross{stroke:#333333;}#mermaid-svg-8hzSEce5QPjByS8w svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8hzSEce5QPjByS8w p{margin:0;}#mermaid-svg-8hzSEce5QPjByS8w .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8hzSEce5QPjByS8w .cluster-label text{fill:#333;}#mermaid-svg-8hzSEce5QPjByS8w .cluster-label span{color:#333;}#mermaid-svg-8hzSEce5QPjByS8w .cluster-label span p{background-color:transparent;}#mermaid-svg-8hzSEce5QPjByS8w .label text,#mermaid-svg-8hzSEce5QPjByS8w span{fill:#333;color:#333;}#mermaid-svg-8hzSEce5QPjByS8w .node rect,#mermaid-svg-8hzSEce5QPjByS8w .node circle,#mermaid-svg-8hzSEce5QPjByS8w .node ellipse,#mermaid-svg-8hzSEce5QPjByS8w .node polygon,#mermaid-svg-8hzSEce5QPjByS8w .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8hzSEce5QPjByS8w .rough-node .label text,#mermaid-svg-8hzSEce5QPjByS8w .node .label text,#mermaid-svg-8hzSEce5QPjByS8w .image-shape .label,#mermaid-svg-8hzSEce5QPjByS8w .icon-shape .label{text-anchor:middle;}#mermaid-svg-8hzSEce5QPjByS8w .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8hzSEce5QPjByS8w .rough-node .label,#mermaid-svg-8hzSEce5QPjByS8w .node .label,#mermaid-svg-8hzSEce5QPjByS8w .image-shape .label,#mermaid-svg-8hzSEce5QPjByS8w .icon-shape .label{text-align:center;}#mermaid-svg-8hzSEce5QPjByS8w .node.clickable{cursor:pointer;}#mermaid-svg-8hzSEce5QPjByS8w .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8hzSEce5QPjByS8w .arrowheadPath{fill:#333333;}#mermaid-svg-8hzSEce5QPjByS8w .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8hzSEce5QPjByS8w .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8hzSEce5QPjByS8w .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8hzSEce5QPjByS8w .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8hzSEce5QPjByS8w .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8hzSEce5QPjByS8w .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8hzSEce5QPjByS8w .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8hzSEce5QPjByS8w .cluster text{fill:#333;}#mermaid-svg-8hzSEce5QPjByS8w .cluster span{color:#333;}#mermaid-svg-8hzSEce5QPjByS8w 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-8hzSEce5QPjByS8w .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8hzSEce5QPjByS8w rect.text{fill:none;stroke-width:0;}#mermaid-svg-8hzSEce5QPjByS8w .icon-shape,#mermaid-svg-8hzSEce5QPjByS8w .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8hzSEce5QPjByS8w .icon-shape p,#mermaid-svg-8hzSEce5QPjByS8w .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8hzSEce5QPjByS8w .icon-shape .label rect,#mermaid-svg-8hzSEce5QPjByS8w .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8hzSEce5QPjByS8w .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8hzSEce5QPjByS8w .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8hzSEce5QPjByS8w :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 分配大对象
计算需要的页数
npages = (size + pageMask) >> pageShift
deduceSweepCredit
调用 mheap.alloc
npages 页
设置 span.limit
= s.base() + size
push 到 mcentral.fullSwept
返回 span
2.9 地址对齐与内存池设计
地址对齐:
- 对象按照大小对齐(如 16B 对象按 16B 对齐)
- span 按页边界对齐(8KB)
- heapArena 按 64MB 对齐
内存池层级:
- mcache:P 本地,无锁
- mcentral:全局,每个 size class 一个
- mheap:全局,大锁
- pageAlloc:页分配器,核心是 treap
2.10 并发分配安全机制
锁策略:
- mcache:无锁(P 本地)
- mcentral:spanSet 使用原子操作
- mheap:全局锁(保护 pages、allspans 等)
内存屏障:
- 分配时使用 StoreLoad 屏障确保初始化完成
- 与 GC 配合使用写屏障
2.11 内存碎片成因与规避
内部碎片:
- 定义:分配的内存比实际需要的大
- 成因:大小类舍入
- 规避:合理的大小类设计
外部碎片:
- 定义:有足够内存但没有连续的页
- 成因:span 释放后离散分布
- 规避:
- 延迟分配(按需分配)
- 及时归还未使用的页给操作系统
- pageAlloc 使用地址序的首次适配算法
2.12 逃逸分析完整原理与编译器判定逻辑
源码位置 :src/cmd/compile/internal/escape/escape.go
#mermaid-svg-XoDjKa2UynL5QGWo{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-XoDjKa2UynL5QGWo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XoDjKa2UynL5QGWo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XoDjKa2UynL5QGWo .error-icon{fill:#552222;}#mermaid-svg-XoDjKa2UynL5QGWo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XoDjKa2UynL5QGWo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XoDjKa2UynL5QGWo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XoDjKa2UynL5QGWo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XoDjKa2UynL5QGWo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XoDjKa2UynL5QGWo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XoDjKa2UynL5QGWo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XoDjKa2UynL5QGWo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XoDjKa2UynL5QGWo .marker.cross{stroke:#333333;}#mermaid-svg-XoDjKa2UynL5QGWo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XoDjKa2UynL5QGWo p{margin:0;}#mermaid-svg-XoDjKa2UynL5QGWo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XoDjKa2UynL5QGWo .cluster-label text{fill:#333;}#mermaid-svg-XoDjKa2UynL5QGWo .cluster-label span{color:#333;}#mermaid-svg-XoDjKa2UynL5QGWo .cluster-label span p{background-color:transparent;}#mermaid-svg-XoDjKa2UynL5QGWo .label text,#mermaid-svg-XoDjKa2UynL5QGWo span{fill:#333;color:#333;}#mermaid-svg-XoDjKa2UynL5QGWo .node rect,#mermaid-svg-XoDjKa2UynL5QGWo .node circle,#mermaid-svg-XoDjKa2UynL5QGWo .node ellipse,#mermaid-svg-XoDjKa2UynL5QGWo .node polygon,#mermaid-svg-XoDjKa2UynL5QGWo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XoDjKa2UynL5QGWo .rough-node .label text,#mermaid-svg-XoDjKa2UynL5QGWo .node .label text,#mermaid-svg-XoDjKa2UynL5QGWo .image-shape .label,#mermaid-svg-XoDjKa2UynL5QGWo .icon-shape .label{text-anchor:middle;}#mermaid-svg-XoDjKa2UynL5QGWo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XoDjKa2UynL5QGWo .rough-node .label,#mermaid-svg-XoDjKa2UynL5QGWo .node .label,#mermaid-svg-XoDjKa2UynL5QGWo .image-shape .label,#mermaid-svg-XoDjKa2UynL5QGWo .icon-shape .label{text-align:center;}#mermaid-svg-XoDjKa2UynL5QGWo .node.clickable{cursor:pointer;}#mermaid-svg-XoDjKa2UynL5QGWo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XoDjKa2UynL5QGWo .arrowheadPath{fill:#333333;}#mermaid-svg-XoDjKa2UynL5QGWo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XoDjKa2UynL5QGWo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XoDjKa2UynL5QGWo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XoDjKa2UynL5QGWo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XoDjKa2UynL5QGWo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XoDjKa2UynL5QGWo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XoDjKa2UynL5QGWo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XoDjKa2UynL5QGWo .cluster text{fill:#333;}#mermaid-svg-XoDjKa2UynL5QGWo .cluster span{color:#333;}#mermaid-svg-XoDjKa2UynL5QGWo 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-XoDjKa2UynL5QGWo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XoDjKa2UynL5QGWo rect.text{fill:none;stroke-width:0;}#mermaid-svg-XoDjKa2UynL5QGWo .icon-shape,#mermaid-svg-XoDjKa2UynL5QGWo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XoDjKa2UynL5QGWo .icon-shape p,#mermaid-svg-XoDjKa2UynL5QGWo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XoDjKa2UynL5QGWo .icon-shape .label rect,#mermaid-svg-XoDjKa2UynL5QGWo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XoDjKa2UynL5QGWo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XoDjKa2UynL5QGWo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XoDjKa2UynL5QGWo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
是
否
是
否
是
否
逃逸分析开始
构建调用图
构建数据流图
分析每个函数
参数/返回值流向
参数被返回?
标记为逃逸
参数被存入堆?
参数被发送到通道?
参数被闭包捕获?
参数泄漏到全局?
不逃逸,栈分配
堆分配
逃逸分析判定规则(来自编译器源码):
-
泄露到堆(leaks to heap):
gofunc f() *int { x := 42 return &x // x 逃逸到堆 } -
被闭包捕获(captured by closure):
gofunc f() func() { x := 42 return func() { // x 被闭包捕获,逃逸 println(x) } } -
发送到通道(sent to channel):
gofunc f(ch chan *int) { x := 42 ch <- &x // x 逃逸到堆 } -
太大的对象(too large):
gofunc f() { var x [1 << 20]int // 过大,栈空间不足,逃逸 use(x) } -
动态类型(dynamic type):
gofunc f(i interface{}) { // i 动态类型,逃逸 println(i) }
2.13 栈扩容与缩容机制
源码位置 :src/runtime/stack.go
#mermaid-svg-VWOSGgfXw7Ooos37{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-VWOSGgfXw7Ooos37 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VWOSGgfXw7Ooos37 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VWOSGgfXw7Ooos37 .error-icon{fill:#552222;}#mermaid-svg-VWOSGgfXw7Ooos37 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VWOSGgfXw7Ooos37 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VWOSGgfXw7Ooos37 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VWOSGgfXw7Ooos37 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VWOSGgfXw7Ooos37 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VWOSGgfXw7Ooos37 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VWOSGgfXw7Ooos37 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VWOSGgfXw7Ooos37 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VWOSGgfXw7Ooos37 .marker.cross{stroke:#333333;}#mermaid-svg-VWOSGgfXw7Ooos37 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VWOSGgfXw7Ooos37 p{margin:0;}#mermaid-svg-VWOSGgfXw7Ooos37 defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-VWOSGgfXw7Ooos37 g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-VWOSGgfXw7Ooos37 g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-VWOSGgfXw7Ooos37 g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-VWOSGgfXw7Ooos37 g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-VWOSGgfXw7Ooos37 g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-VWOSGgfXw7Ooos37 .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-VWOSGgfXw7Ooos37 .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-VWOSGgfXw7Ooos37 .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-VWOSGgfXw7Ooos37 .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-VWOSGgfXw7Ooos37 .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-VWOSGgfXw7Ooos37 .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-VWOSGgfXw7Ooos37 .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-VWOSGgfXw7Ooos37 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VWOSGgfXw7Ooos37 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VWOSGgfXw7Ooos37 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VWOSGgfXw7Ooos37 .edgeLabel .label text{fill:#333;}#mermaid-svg-VWOSGgfXw7Ooos37 .label div .edgeLabel{color:#333;}#mermaid-svg-VWOSGgfXw7Ooos37 .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-VWOSGgfXw7Ooos37 .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-VWOSGgfXw7Ooos37 .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-VWOSGgfXw7Ooos37 .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-VWOSGgfXw7Ooos37 .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-VWOSGgfXw7Ooos37 .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VWOSGgfXw7Ooos37 .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VWOSGgfXw7Ooos37 #statediagram-barbEnd{fill:#333333;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VWOSGgfXw7Ooos37 .cluster-label,#mermaid-svg-VWOSGgfXw7Ooos37 .nodeLabel{color:#131300;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-VWOSGgfXw7Ooos37 .note-edge{stroke-dasharray:5;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-note text{fill:black;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram-note .nodeLabel{color:black;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagram .edgeLabel{color:red;}#mermaid-svg-VWOSGgfXw7Ooos37 #dependencyStart,#mermaid-svg-VWOSGgfXw7Ooos37 #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-VWOSGgfXw7Ooos37 .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VWOSGgfXw7Ooos37 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 新 goroutine
栈溢出
newstack()
栈溢出
newstack()
栈溢出
newstack()
栈溢出
newstack()
GC 时
shrinkstack()
GC 时
shrinkstack()
GC 时
shrinkstack()
GC 时
shrinkstack()
S2KB
S4KB
S8KB
S16KB
S32KB
栈扩容流程:
#mermaid-svg-e1AwL6Ldiecufif8{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-e1AwL6Ldiecufif8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e1AwL6Ldiecufif8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e1AwL6Ldiecufif8 .error-icon{fill:#552222;}#mermaid-svg-e1AwL6Ldiecufif8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-e1AwL6Ldiecufif8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e1AwL6Ldiecufif8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e1AwL6Ldiecufif8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e1AwL6Ldiecufif8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e1AwL6Ldiecufif8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e1AwL6Ldiecufif8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e1AwL6Ldiecufif8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-e1AwL6Ldiecufif8 .marker.cross{stroke:#333333;}#mermaid-svg-e1AwL6Ldiecufif8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-e1AwL6Ldiecufif8 p{margin:0;}#mermaid-svg-e1AwL6Ldiecufif8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-e1AwL6Ldiecufif8 .cluster-label text{fill:#333;}#mermaid-svg-e1AwL6Ldiecufif8 .cluster-label span{color:#333;}#mermaid-svg-e1AwL6Ldiecufif8 .cluster-label span p{background-color:transparent;}#mermaid-svg-e1AwL6Ldiecufif8 .label text,#mermaid-svg-e1AwL6Ldiecufif8 span{fill:#333;color:#333;}#mermaid-svg-e1AwL6Ldiecufif8 .node rect,#mermaid-svg-e1AwL6Ldiecufif8 .node circle,#mermaid-svg-e1AwL6Ldiecufif8 .node ellipse,#mermaid-svg-e1AwL6Ldiecufif8 .node polygon,#mermaid-svg-e1AwL6Ldiecufif8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-e1AwL6Ldiecufif8 .rough-node .label text,#mermaid-svg-e1AwL6Ldiecufif8 .node .label text,#mermaid-svg-e1AwL6Ldiecufif8 .image-shape .label,#mermaid-svg-e1AwL6Ldiecufif8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-e1AwL6Ldiecufif8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-e1AwL6Ldiecufif8 .rough-node .label,#mermaid-svg-e1AwL6Ldiecufif8 .node .label,#mermaid-svg-e1AwL6Ldiecufif8 .image-shape .label,#mermaid-svg-e1AwL6Ldiecufif8 .icon-shape .label{text-align:center;}#mermaid-svg-e1AwL6Ldiecufif8 .node.clickable{cursor:pointer;}#mermaid-svg-e1AwL6Ldiecufif8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-e1AwL6Ldiecufif8 .arrowheadPath{fill:#333333;}#mermaid-svg-e1AwL6Ldiecufif8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-e1AwL6Ldiecufif8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-e1AwL6Ldiecufif8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e1AwL6Ldiecufif8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-e1AwL6Ldiecufif8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e1AwL6Ldiecufif8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-e1AwL6Ldiecufif8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-e1AwL6Ldiecufif8 .cluster text{fill:#333;}#mermaid-svg-e1AwL6Ldiecufif8 .cluster span{color:#333;}#mermaid-svg-e1AwL6Ldiecufif8 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-e1AwL6Ldiecufif8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-e1AwL6Ldiecufif8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-e1AwL6Ldiecufif8 .icon-shape,#mermaid-svg-e1AwL6Ldiecufif8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e1AwL6Ldiecufif8 .icon-shape p,#mermaid-svg-e1AwL6Ldiecufif8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-e1AwL6Ldiecufif8 .icon-shape .label rect,#mermaid-svg-e1AwL6Ldiecufif8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e1AwL6Ldiecufif8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-e1AwL6Ldiecufif8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-e1AwL6Ldiecufif8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} morestack 调用
进入 newstack
计算新栈大小
2x
分配新栈
复制栈内容
copystack
调整指针
gentraceback
更新 G.stack
返回执行
栈缩容触发条件:
- GC 标记阶段结束后
- 栈使用量 < 1/4 的栈大小
- 缩容到原大小的 1/2
2.14 完整的对象分配流程图
#mermaid-svg-wUsHuN9fQ7x3P2S1{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-wUsHuN9fQ7x3P2S1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .error-icon{fill:#552222;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .marker.cross{stroke:#333333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 p{margin:0;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .cluster-label text{fill:#333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .cluster-label span{color:#333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .cluster-label span p{background-color:transparent;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .label text,#mermaid-svg-wUsHuN9fQ7x3P2S1 span{fill:#333;color:#333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .node rect,#mermaid-svg-wUsHuN9fQ7x3P2S1 .node circle,#mermaid-svg-wUsHuN9fQ7x3P2S1 .node ellipse,#mermaid-svg-wUsHuN9fQ7x3P2S1 .node polygon,#mermaid-svg-wUsHuN9fQ7x3P2S1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .rough-node .label text,#mermaid-svg-wUsHuN9fQ7x3P2S1 .node .label text,#mermaid-svg-wUsHuN9fQ7x3P2S1 .image-shape .label,#mermaid-svg-wUsHuN9fQ7x3P2S1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .rough-node .label,#mermaid-svg-wUsHuN9fQ7x3P2S1 .node .label,#mermaid-svg-wUsHuN9fQ7x3P2S1 .image-shape .label,#mermaid-svg-wUsHuN9fQ7x3P2S1 .icon-shape .label{text-align:center;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .node.clickable{cursor:pointer;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .arrowheadPath{fill:#333333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wUsHuN9fQ7x3P2S1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wUsHuN9fQ7x3P2S1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wUsHuN9fQ7x3P2S1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .cluster text{fill:#333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .cluster span{color:#333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 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-wUsHuN9fQ7x3P2S1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wUsHuN9fQ7x3P2S1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .icon-shape,#mermaid-svg-wUsHuN9fQ7x3P2S1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .icon-shape p,#mermaid-svg-wUsHuN9fQ7x3P2S1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .icon-shape .label rect,#mermaid-svg-wUsHuN9fQ7x3P2S1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wUsHuN9fQ7x3P2S1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wUsHuN9fQ7x3P2S1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wUsHuN9fQ7x3P2S1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
是
是
否
是
否
否
newobject/mallocgc
开始分配
size == 0?
返回 zerobase
size <= maxTinySize
&& noscan?
mallocgcTiny
微对象分配
返回对象指针
size <= maxSmallSize?
计算 size class
roundupsize
获取当前 G 的 mcache
noscan &&
hasReusableNoscan?
从 reusableNoscan 分配
获取对应 spanClass 的 span
span 有空间?
使用 allocCache
快速分配
调用 refill
获取新 span
从 mcentral 获取 span
从 mheap 分配 span
如需要
初始化 span
大对象分配
mcache.allocLarge
计算页数
npages
从 mheap 分配 span
3. Go 垃圾回收完整底层实现原理(重点深挖)
3.1 Go GC 演进历史
#mermaid-svg-BzxUsrPyZiDutpcZ{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-BzxUsrPyZiDutpcZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BzxUsrPyZiDutpcZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BzxUsrPyZiDutpcZ .error-icon{fill:#552222;}#mermaid-svg-BzxUsrPyZiDutpcZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BzxUsrPyZiDutpcZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BzxUsrPyZiDutpcZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BzxUsrPyZiDutpcZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BzxUsrPyZiDutpcZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BzxUsrPyZiDutpcZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BzxUsrPyZiDutpcZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BzxUsrPyZiDutpcZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BzxUsrPyZiDutpcZ .marker.cross{stroke:#333333;}#mermaid-svg-BzxUsrPyZiDutpcZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BzxUsrPyZiDutpcZ p{margin:0;}#mermaid-svg-BzxUsrPyZiDutpcZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BzxUsrPyZiDutpcZ .cluster-label text{fill:#333;}#mermaid-svg-BzxUsrPyZiDutpcZ .cluster-label span{color:#333;}#mermaid-svg-BzxUsrPyZiDutpcZ .cluster-label span p{background-color:transparent;}#mermaid-svg-BzxUsrPyZiDutpcZ .label text,#mermaid-svg-BzxUsrPyZiDutpcZ span{fill:#333;color:#333;}#mermaid-svg-BzxUsrPyZiDutpcZ .node rect,#mermaid-svg-BzxUsrPyZiDutpcZ .node circle,#mermaid-svg-BzxUsrPyZiDutpcZ .node ellipse,#mermaid-svg-BzxUsrPyZiDutpcZ .node polygon,#mermaid-svg-BzxUsrPyZiDutpcZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BzxUsrPyZiDutpcZ .rough-node .label text,#mermaid-svg-BzxUsrPyZiDutpcZ .node .label text,#mermaid-svg-BzxUsrPyZiDutpcZ .image-shape .label,#mermaid-svg-BzxUsrPyZiDutpcZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-BzxUsrPyZiDutpcZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BzxUsrPyZiDutpcZ .rough-node .label,#mermaid-svg-BzxUsrPyZiDutpcZ .node .label,#mermaid-svg-BzxUsrPyZiDutpcZ .image-shape .label,#mermaid-svg-BzxUsrPyZiDutpcZ .icon-shape .label{text-align:center;}#mermaid-svg-BzxUsrPyZiDutpcZ .node.clickable{cursor:pointer;}#mermaid-svg-BzxUsrPyZiDutpcZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BzxUsrPyZiDutpcZ .arrowheadPath{fill:#333333;}#mermaid-svg-BzxUsrPyZiDutpcZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BzxUsrPyZiDutpcZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BzxUsrPyZiDutpcZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BzxUsrPyZiDutpcZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BzxUsrPyZiDutpcZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BzxUsrPyZiDutpcZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BzxUsrPyZiDutpcZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BzxUsrPyZiDutpcZ .cluster text{fill:#333;}#mermaid-svg-BzxUsrPyZiDutpcZ .cluster span{color:#333;}#mermaid-svg-BzxUsrPyZiDutpcZ 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-BzxUsrPyZiDutpcZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BzxUsrPyZiDutpcZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-BzxUsrPyZiDutpcZ .icon-shape,#mermaid-svg-BzxUsrPyZiDutpcZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BzxUsrPyZiDutpcZ .icon-shape p,#mermaid-svg-BzxUsrPyZiDutpcZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BzxUsrPyZiDutpcZ .icon-shape .label rect,#mermaid-svg-BzxUsrPyZiDutpcZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BzxUsrPyZiDutpcZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BzxUsrPyZiDutpcZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BzxUsrPyZiDutpcZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Go 1.18+
Go 1.15-1.17
Go 1.13-1.14
Go 1.9-1.12
Go 1.8
Go 1.6-1.7
Go 1.5
Go 1.0-1.4
串行标记-清扫
STW ~ 几百ms
三色并发标记
STW ~ 10ms
写入屏障优化
STW ~ 1ms
混合写入屏障
STW < 1ms
Pacer 优化
并发清扫
页分配器重构
异步预取
非均匀内存访问
目标调整
软内存限制 GOMEMLIMIT
更激进的回收
3.2 三色标记法完整原理
源码位置 :src/runtime/mgc.go
三色状态定义
#mermaid-svg-uWUFhukc5aYUnQmU{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-uWUFhukc5aYUnQmU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uWUFhukc5aYUnQmU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uWUFhukc5aYUnQmU .error-icon{fill:#552222;}#mermaid-svg-uWUFhukc5aYUnQmU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uWUFhukc5aYUnQmU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uWUFhukc5aYUnQmU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uWUFhukc5aYUnQmU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uWUFhukc5aYUnQmU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uWUFhukc5aYUnQmU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uWUFhukc5aYUnQmU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uWUFhukc5aYUnQmU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uWUFhukc5aYUnQmU .marker.cross{stroke:#333333;}#mermaid-svg-uWUFhukc5aYUnQmU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uWUFhukc5aYUnQmU p{margin:0;}#mermaid-svg-uWUFhukc5aYUnQmU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uWUFhukc5aYUnQmU .cluster-label text{fill:#333;}#mermaid-svg-uWUFhukc5aYUnQmU .cluster-label span{color:#333;}#mermaid-svg-uWUFhukc5aYUnQmU .cluster-label span p{background-color:transparent;}#mermaid-svg-uWUFhukc5aYUnQmU .label text,#mermaid-svg-uWUFhukc5aYUnQmU span{fill:#333;color:#333;}#mermaid-svg-uWUFhukc5aYUnQmU .node rect,#mermaid-svg-uWUFhukc5aYUnQmU .node circle,#mermaid-svg-uWUFhukc5aYUnQmU .node ellipse,#mermaid-svg-uWUFhukc5aYUnQmU .node polygon,#mermaid-svg-uWUFhukc5aYUnQmU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uWUFhukc5aYUnQmU .rough-node .label text,#mermaid-svg-uWUFhukc5aYUnQmU .node .label text,#mermaid-svg-uWUFhukc5aYUnQmU .image-shape .label,#mermaid-svg-uWUFhukc5aYUnQmU .icon-shape .label{text-anchor:middle;}#mermaid-svg-uWUFhukc5aYUnQmU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uWUFhukc5aYUnQmU .rough-node .label,#mermaid-svg-uWUFhukc5aYUnQmU .node .label,#mermaid-svg-uWUFhukc5aYUnQmU .image-shape .label,#mermaid-svg-uWUFhukc5aYUnQmU .icon-shape .label{text-align:center;}#mermaid-svg-uWUFhukc5aYUnQmU .node.clickable{cursor:pointer;}#mermaid-svg-uWUFhukc5aYUnQmU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uWUFhukc5aYUnQmU .arrowheadPath{fill:#333333;}#mermaid-svg-uWUFhukc5aYUnQmU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uWUFhukc5aYUnQmU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uWUFhukc5aYUnQmU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uWUFhukc5aYUnQmU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uWUFhukc5aYUnQmU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uWUFhukc5aYUnQmU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uWUFhukc5aYUnQmU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uWUFhukc5aYUnQmU .cluster text{fill:#333;}#mermaid-svg-uWUFhukc5aYUnQmU .cluster span{color:#333;}#mermaid-svg-uWUFhukc5aYUnQmU 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-uWUFhukc5aYUnQmU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uWUFhukc5aYUnQmU rect.text{fill:none;stroke-width:0;}#mermaid-svg-uWUFhukc5aYUnQmU .icon-shape,#mermaid-svg-uWUFhukc5aYUnQmU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uWUFhukc5aYUnQmU .icon-shape p,#mermaid-svg-uWUFhukc5aYUnQmU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uWUFhukc5aYUnQmU .icon-shape .label rect,#mermaid-svg-uWUFhukc5aYUnQmU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uWUFhukc5aYUnQmU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uWUFhukc5aYUnQmU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uWUFhukc5aYUnQmU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 黑色对象
灰色对象
白色对象
扫描
标记
写屏障
引用
白色
未标记
待回收
灰色
已标记
成员待扫描
黑色
已标记
成员已扫描
三色定义:
- 白色:未被标记的对象,最终会被回收
- 灰色:已被标记,但成员对象还未扫描
- 黑色:已被标记,且所有成员对象都已扫描
三色不变性
强三色不变性:
- 黑色对象不能直接引用白色对象
弱三色不变性:
- 黑色对象可以引用白色对象,但必须有灰色对象保护白色对象
Go 使用的是弱三色不变性 + 写屏障。
完整的标记流程
Write Barrier Goroutine Mark Worker GC Controller Write Barrier Goroutine Mark Worker GC Controller #mermaid-svg-4P6eFyrTR5w92T5e{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-4P6eFyrTR5w92T5e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4P6eFyrTR5w92T5e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4P6eFyrTR5w92T5e .error-icon{fill:#552222;}#mermaid-svg-4P6eFyrTR5w92T5e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4P6eFyrTR5w92T5e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4P6eFyrTR5w92T5e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4P6eFyrTR5w92T5e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4P6eFyrTR5w92T5e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4P6eFyrTR5w92T5e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4P6eFyrTR5w92T5e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4P6eFyrTR5w92T5e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4P6eFyrTR5w92T5e .marker.cross{stroke:#333333;}#mermaid-svg-4P6eFyrTR5w92T5e svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4P6eFyrTR5w92T5e p{margin:0;}#mermaid-svg-4P6eFyrTR5w92T5e .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4P6eFyrTR5w92T5e text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-4P6eFyrTR5w92T5e .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4P6eFyrTR5w92T5e .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-4P6eFyrTR5w92T5e .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-4P6eFyrTR5w92T5e .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-4P6eFyrTR5w92T5e #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-4P6eFyrTR5w92T5e .sequenceNumber{fill:white;}#mermaid-svg-4P6eFyrTR5w92T5e #sequencenumber{fill:#333;}#mermaid-svg-4P6eFyrTR5w92T5e #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-4P6eFyrTR5w92T5e .messageText{fill:#333;stroke:none;}#mermaid-svg-4P6eFyrTR5w92T5e .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4P6eFyrTR5w92T5e .labelText,#mermaid-svg-4P6eFyrTR5w92T5e .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-4P6eFyrTR5w92T5e .loopText,#mermaid-svg-4P6eFyrTR5w92T5e .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-4P6eFyrTR5w92T5e .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-4P6eFyrTR5w92T5e .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4P6eFyrTR5w92T5e .noteText,#mermaid-svg-4P6eFyrTR5w92T5e .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-4P6eFyrTR5w92T5e .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4P6eFyrTR5w92T5e .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4P6eFyrTR5w92T5e .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4P6eFyrTR5w92T5e .actorPopupMenu{position:absolute;}#mermaid-svg-4P6eFyrTR5w92T5e .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-4P6eFyrTR5w92T5e .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4P6eFyrTR5w92T5e .actor-man circle,#mermaid-svg-4P6eFyrTR5w92T5e line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-4P6eFyrTR5w92T5e :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop 标记循环 STW: 标记预备阶段 启用写屏障 启动标记工作协程 开始世界 (STW 结束) 根对象标记 扫描栈 扫描全局变量 扫描 finalizer 队列 获取灰色对象 扫描对象成员 标记白色成员为灰色 将对象标记为黑色 写指针操作 执行写屏障 将目标对象标记为灰色 检查完成 STW: 标记终止阶段 禁用写屏障 开始清扫阶段
3.3 漏标问题成因与解决方案
漏标问题
#mermaid-svg-mWMrHPLnyiD4Mznf{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-mWMrHPLnyiD4Mznf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mWMrHPLnyiD4Mznf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mWMrHPLnyiD4Mznf .error-icon{fill:#552222;}#mermaid-svg-mWMrHPLnyiD4Mznf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mWMrHPLnyiD4Mznf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mWMrHPLnyiD4Mznf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mWMrHPLnyiD4Mznf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mWMrHPLnyiD4Mznf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mWMrHPLnyiD4Mznf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mWMrHPLnyiD4Mznf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mWMrHPLnyiD4Mznf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mWMrHPLnyiD4Mznf .marker.cross{stroke:#333333;}#mermaid-svg-mWMrHPLnyiD4Mznf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mWMrHPLnyiD4Mznf p{margin:0;}#mermaid-svg-mWMrHPLnyiD4Mznf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mWMrHPLnyiD4Mznf .cluster-label text{fill:#333;}#mermaid-svg-mWMrHPLnyiD4Mznf .cluster-label span{color:#333;}#mermaid-svg-mWMrHPLnyiD4Mznf .cluster-label span p{background-color:transparent;}#mermaid-svg-mWMrHPLnyiD4Mznf .label text,#mermaid-svg-mWMrHPLnyiD4Mznf span{fill:#333;color:#333;}#mermaid-svg-mWMrHPLnyiD4Mznf .node rect,#mermaid-svg-mWMrHPLnyiD4Mznf .node circle,#mermaid-svg-mWMrHPLnyiD4Mznf .node ellipse,#mermaid-svg-mWMrHPLnyiD4Mznf .node polygon,#mermaid-svg-mWMrHPLnyiD4Mznf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mWMrHPLnyiD4Mznf .rough-node .label text,#mermaid-svg-mWMrHPLnyiD4Mznf .node .label text,#mermaid-svg-mWMrHPLnyiD4Mznf .image-shape .label,#mermaid-svg-mWMrHPLnyiD4Mznf .icon-shape .label{text-anchor:middle;}#mermaid-svg-mWMrHPLnyiD4Mznf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mWMrHPLnyiD4Mznf .rough-node .label,#mermaid-svg-mWMrHPLnyiD4Mznf .node .label,#mermaid-svg-mWMrHPLnyiD4Mznf .image-shape .label,#mermaid-svg-mWMrHPLnyiD4Mznf .icon-shape .label{text-align:center;}#mermaid-svg-mWMrHPLnyiD4Mznf .node.clickable{cursor:pointer;}#mermaid-svg-mWMrHPLnyiD4Mznf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mWMrHPLnyiD4Mznf .arrowheadPath{fill:#333333;}#mermaid-svg-mWMrHPLnyiD4Mznf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mWMrHPLnyiD4Mznf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mWMrHPLnyiD4Mznf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mWMrHPLnyiD4Mznf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mWMrHPLnyiD4Mznf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mWMrHPLnyiD4Mznf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mWMrHPLnyiD4Mznf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mWMrHPLnyiD4Mznf .cluster text{fill:#333;}#mermaid-svg-mWMrHPLnyiD4Mznf .cluster span{color:#333;}#mermaid-svg-mWMrHPLnyiD4Mznf 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-mWMrHPLnyiD4Mznf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mWMrHPLnyiD4Mznf rect.text{fill:none;stroke-width:0;}#mermaid-svg-mWMrHPLnyiD4Mznf .icon-shape,#mermaid-svg-mWMrHPLnyiD4Mznf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mWMrHPLnyiD4Mznf .icon-shape p,#mermaid-svg-mWMrHPLnyiD4Mznf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mWMrHPLnyiD4Mznf .icon-shape .label rect,#mermaid-svg-mWMrHPLnyiD4Mznf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mWMrHPLnyiD4Mznf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mWMrHPLnyiD4Mznf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mWMrHPLnyiD4Mznf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 删除引用
新增引用
可能漏标
黑色对象 A
白色对象 C
灰色对象 B
被错误回收
漏标条件(同时满足):
- 黑色对象新增对白色对象的引用
- 灰色对象删除对白色对象的引用
解决方案:写屏障技术
源码位置 :src/runtime/mbarrier.go
Go 1.8+ 使用混合写屏障(Hybrid Write Barrier)。
#mermaid-svg-UBrAyTbLx7lhMBQN{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-UBrAyTbLx7lhMBQN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UBrAyTbLx7lhMBQN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UBrAyTbLx7lhMBQN .error-icon{fill:#552222;}#mermaid-svg-UBrAyTbLx7lhMBQN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UBrAyTbLx7lhMBQN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UBrAyTbLx7lhMBQN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UBrAyTbLx7lhMBQN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UBrAyTbLx7lhMBQN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UBrAyTbLx7lhMBQN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UBrAyTbLx7lhMBQN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UBrAyTbLx7lhMBQN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UBrAyTbLx7lhMBQN .marker.cross{stroke:#333333;}#mermaid-svg-UBrAyTbLx7lhMBQN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UBrAyTbLx7lhMBQN p{margin:0;}#mermaid-svg-UBrAyTbLx7lhMBQN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UBrAyTbLx7lhMBQN .cluster-label text{fill:#333;}#mermaid-svg-UBrAyTbLx7lhMBQN .cluster-label span{color:#333;}#mermaid-svg-UBrAyTbLx7lhMBQN .cluster-label span p{background-color:transparent;}#mermaid-svg-UBrAyTbLx7lhMBQN .label text,#mermaid-svg-UBrAyTbLx7lhMBQN span{fill:#333;color:#333;}#mermaid-svg-UBrAyTbLx7lhMBQN .node rect,#mermaid-svg-UBrAyTbLx7lhMBQN .node circle,#mermaid-svg-UBrAyTbLx7lhMBQN .node ellipse,#mermaid-svg-UBrAyTbLx7lhMBQN .node polygon,#mermaid-svg-UBrAyTbLx7lhMBQN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UBrAyTbLx7lhMBQN .rough-node .label text,#mermaid-svg-UBrAyTbLx7lhMBQN .node .label text,#mermaid-svg-UBrAyTbLx7lhMBQN .image-shape .label,#mermaid-svg-UBrAyTbLx7lhMBQN .icon-shape .label{text-anchor:middle;}#mermaid-svg-UBrAyTbLx7lhMBQN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UBrAyTbLx7lhMBQN .rough-node .label,#mermaid-svg-UBrAyTbLx7lhMBQN .node .label,#mermaid-svg-UBrAyTbLx7lhMBQN .image-shape .label,#mermaid-svg-UBrAyTbLx7lhMBQN .icon-shape .label{text-align:center;}#mermaid-svg-UBrAyTbLx7lhMBQN .node.clickable{cursor:pointer;}#mermaid-svg-UBrAyTbLx7lhMBQN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UBrAyTbLx7lhMBQN .arrowheadPath{fill:#333333;}#mermaid-svg-UBrAyTbLx7lhMBQN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UBrAyTbLx7lhMBQN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UBrAyTbLx7lhMBQN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UBrAyTbLx7lhMBQN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UBrAyTbLx7lhMBQN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UBrAyTbLx7lhMBQN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UBrAyTbLx7lhMBQN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UBrAyTbLx7lhMBQN .cluster text{fill:#333;}#mermaid-svg-UBrAyTbLx7lhMBQN .cluster span{color:#333;}#mermaid-svg-UBrAyTbLx7lhMBQN 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-UBrAyTbLx7lhMBQN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UBrAyTbLx7lhMBQN rect.text{fill:none;stroke-width:0;}#mermaid-svg-UBrAyTbLx7lhMBQN .icon-shape,#mermaid-svg-UBrAyTbLx7lhMBQN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UBrAyTbLx7lhMBQN .icon-shape p,#mermaid-svg-UBrAyTbLx7lhMBQN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UBrAyTbLx7lhMBQN .icon-shape .label rect,#mermaid-svg-UBrAyTbLx7lhMBQN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UBrAyTbLx7lhMBQN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UBrAyTbLx7lhMBQN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UBrAyTbLx7lhMBQN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 写屏障操作
写屏障触发
slot = ptr
指针赋值
标记 *slot 为灰色
(如果是白色)
标记 ptr 为灰色
(如果是白色)
混合写屏障逻辑(来自源码注释):
go
// 混合写屏障:
// writePointer(slot, ptr) {
// shade(*slot) // 标记旧值
// shade(ptr) // 标记新值
// *slot = ptr
// }
写屏障实现:
#mermaid-svg-TJEYKzVTltDbP9Aj{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-TJEYKzVTltDbP9Aj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TJEYKzVTltDbP9Aj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TJEYKzVTltDbP9Aj .error-icon{fill:#552222;}#mermaid-svg-TJEYKzVTltDbP9Aj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TJEYKzVTltDbP9Aj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TJEYKzVTltDbP9Aj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TJEYKzVTltDbP9Aj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TJEYKzVTltDbP9Aj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TJEYKzVTltDbP9Aj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TJEYKzVTltDbP9Aj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TJEYKzVTltDbP9Aj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TJEYKzVTltDbP9Aj .marker.cross{stroke:#333333;}#mermaid-svg-TJEYKzVTltDbP9Aj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TJEYKzVTltDbP9Aj p{margin:0;}#mermaid-svg-TJEYKzVTltDbP9Aj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TJEYKzVTltDbP9Aj .cluster-label text{fill:#333;}#mermaid-svg-TJEYKzVTltDbP9Aj .cluster-label span{color:#333;}#mermaid-svg-TJEYKzVTltDbP9Aj .cluster-label span p{background-color:transparent;}#mermaid-svg-TJEYKzVTltDbP9Aj .label text,#mermaid-svg-TJEYKzVTltDbP9Aj span{fill:#333;color:#333;}#mermaid-svg-TJEYKzVTltDbP9Aj .node rect,#mermaid-svg-TJEYKzVTltDbP9Aj .node circle,#mermaid-svg-TJEYKzVTltDbP9Aj .node ellipse,#mermaid-svg-TJEYKzVTltDbP9Aj .node polygon,#mermaid-svg-TJEYKzVTltDbP9Aj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TJEYKzVTltDbP9Aj .rough-node .label text,#mermaid-svg-TJEYKzVTltDbP9Aj .node .label text,#mermaid-svg-TJEYKzVTltDbP9Aj .image-shape .label,#mermaid-svg-TJEYKzVTltDbP9Aj .icon-shape .label{text-anchor:middle;}#mermaid-svg-TJEYKzVTltDbP9Aj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TJEYKzVTltDbP9Aj .rough-node .label,#mermaid-svg-TJEYKzVTltDbP9Aj .node .label,#mermaid-svg-TJEYKzVTltDbP9Aj .image-shape .label,#mermaid-svg-TJEYKzVTltDbP9Aj .icon-shape .label{text-align:center;}#mermaid-svg-TJEYKzVTltDbP9Aj .node.clickable{cursor:pointer;}#mermaid-svg-TJEYKzVTltDbP9Aj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TJEYKzVTltDbP9Aj .arrowheadPath{fill:#333333;}#mermaid-svg-TJEYKzVTltDbP9Aj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TJEYKzVTltDbP9Aj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TJEYKzVTltDbP9Aj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TJEYKzVTltDbP9Aj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TJEYKzVTltDbP9Aj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TJEYKzVTltDbP9Aj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TJEYKzVTltDbP9Aj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TJEYKzVTltDbP9Aj .cluster text{fill:#333;}#mermaid-svg-TJEYKzVTltDbP9Aj .cluster span{color:#333;}#mermaid-svg-TJEYKzVTltDbP9Aj 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-TJEYKzVTltDbP9Aj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TJEYKzVTltDbP9Aj rect.text{fill:none;stroke-width:0;}#mermaid-svg-TJEYKzVTltDbP9Aj .icon-shape,#mermaid-svg-TJEYKzVTltDbP9Aj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TJEYKzVTltDbP9Aj .icon-shape p,#mermaid-svg-TJEYKzVTltDbP9Aj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TJEYKzVTltDbP9Aj .icon-shape .label rect,#mermaid-svg-TJEYKzVTltDbP9Aj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TJEYKzVTltDbP9Aj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TJEYKzVTltDbP9Aj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TJEYKzVTltDbP9Aj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
是
否
指针写入触发
写屏障启用?
直接写入
ptr 是
堆指针?
标记 ptr 为灰色
shade(ptr)
*slot 是
堆指针?
标记 *slot 为灰色
shade(*slot)
3.4 GC 完整阶段详解
源码位置 :src/runtime/mgc.go 的 gcStart 函数
#mermaid-svg-r5iewCDQNA0TKg8J{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-r5iewCDQNA0TKg8J .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-r5iewCDQNA0TKg8J .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-r5iewCDQNA0TKg8J .error-icon{fill:#552222;}#mermaid-svg-r5iewCDQNA0TKg8J .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-r5iewCDQNA0TKg8J .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-r5iewCDQNA0TKg8J .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-r5iewCDQNA0TKg8J .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-r5iewCDQNA0TKg8J .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-r5iewCDQNA0TKg8J .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-r5iewCDQNA0TKg8J .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-r5iewCDQNA0TKg8J .marker{fill:#333333;stroke:#333333;}#mermaid-svg-r5iewCDQNA0TKg8J .marker.cross{stroke:#333333;}#mermaid-svg-r5iewCDQNA0TKg8J svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-r5iewCDQNA0TKg8J p{margin:0;}#mermaid-svg-r5iewCDQNA0TKg8J .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-r5iewCDQNA0TKg8J .cluster-label text{fill:#333;}#mermaid-svg-r5iewCDQNA0TKg8J .cluster-label span{color:#333;}#mermaid-svg-r5iewCDQNA0TKg8J .cluster-label span p{background-color:transparent;}#mermaid-svg-r5iewCDQNA0TKg8J .label text,#mermaid-svg-r5iewCDQNA0TKg8J span{fill:#333;color:#333;}#mermaid-svg-r5iewCDQNA0TKg8J .node rect,#mermaid-svg-r5iewCDQNA0TKg8J .node circle,#mermaid-svg-r5iewCDQNA0TKg8J .node ellipse,#mermaid-svg-r5iewCDQNA0TKg8J .node polygon,#mermaid-svg-r5iewCDQNA0TKg8J .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-r5iewCDQNA0TKg8J .rough-node .label text,#mermaid-svg-r5iewCDQNA0TKg8J .node .label text,#mermaid-svg-r5iewCDQNA0TKg8J .image-shape .label,#mermaid-svg-r5iewCDQNA0TKg8J .icon-shape .label{text-anchor:middle;}#mermaid-svg-r5iewCDQNA0TKg8J .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-r5iewCDQNA0TKg8J .rough-node .label,#mermaid-svg-r5iewCDQNA0TKg8J .node .label,#mermaid-svg-r5iewCDQNA0TKg8J .image-shape .label,#mermaid-svg-r5iewCDQNA0TKg8J .icon-shape .label{text-align:center;}#mermaid-svg-r5iewCDQNA0TKg8J .node.clickable{cursor:pointer;}#mermaid-svg-r5iewCDQNA0TKg8J .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-r5iewCDQNA0TKg8J .arrowheadPath{fill:#333333;}#mermaid-svg-r5iewCDQNA0TKg8J .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-r5iewCDQNA0TKg8J .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-r5iewCDQNA0TKg8J .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r5iewCDQNA0TKg8J .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-r5iewCDQNA0TKg8J .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r5iewCDQNA0TKg8J .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-r5iewCDQNA0TKg8J .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-r5iewCDQNA0TKg8J .cluster text{fill:#333;}#mermaid-svg-r5iewCDQNA0TKg8J .cluster span{color:#333;}#mermaid-svg-r5iewCDQNA0TKg8J 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-r5iewCDQNA0TKg8J .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-r5iewCDQNA0TKg8J rect.text{fill:none;stroke-width:0;}#mermaid-svg-r5iewCDQNA0TKg8J .icon-shape,#mermaid-svg-r5iewCDQNA0TKg8J .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r5iewCDQNA0TKg8J .icon-shape p,#mermaid-svg-r5iewCDQNA0TKg8J .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-r5iewCDQNA0TKg8J .icon-shape .label rect,#mermaid-svg-r5iewCDQNA0TKg8J .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r5iewCDQNA0TKg8J .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-r5iewCDQNA0TKg8J .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-r5iewCDQNA0TKg8J :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GC 周期
下一次触发
STW: 1. 标记预备
sweep termination
~ tens µs
2. 并发标记
concurrent mark
~ 多数时间
STW: 3. 标记终止
mark termination
~ hundreds µs
4. 并发清扫
concurrent sweep
与用户代码并行
阶段1: 标记预备(Sweep Termination)- STW
#mermaid-svg-P36Zdit0yUz1z8lX{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-P36Zdit0yUz1z8lX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-P36Zdit0yUz1z8lX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-P36Zdit0yUz1z8lX .error-icon{fill:#552222;}#mermaid-svg-P36Zdit0yUz1z8lX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-P36Zdit0yUz1z8lX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-P36Zdit0yUz1z8lX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-P36Zdit0yUz1z8lX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-P36Zdit0yUz1z8lX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-P36Zdit0yUz1z8lX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-P36Zdit0yUz1z8lX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-P36Zdit0yUz1z8lX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-P36Zdit0yUz1z8lX .marker.cross{stroke:#333333;}#mermaid-svg-P36Zdit0yUz1z8lX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-P36Zdit0yUz1z8lX p{margin:0;}#mermaid-svg-P36Zdit0yUz1z8lX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-P36Zdit0yUz1z8lX .cluster-label text{fill:#333;}#mermaid-svg-P36Zdit0yUz1z8lX .cluster-label span{color:#333;}#mermaid-svg-P36Zdit0yUz1z8lX .cluster-label span p{background-color:transparent;}#mermaid-svg-P36Zdit0yUz1z8lX .label text,#mermaid-svg-P36Zdit0yUz1z8lX span{fill:#333;color:#333;}#mermaid-svg-P36Zdit0yUz1z8lX .node rect,#mermaid-svg-P36Zdit0yUz1z8lX .node circle,#mermaid-svg-P36Zdit0yUz1z8lX .node ellipse,#mermaid-svg-P36Zdit0yUz1z8lX .node polygon,#mermaid-svg-P36Zdit0yUz1z8lX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-P36Zdit0yUz1z8lX .rough-node .label text,#mermaid-svg-P36Zdit0yUz1z8lX .node .label text,#mermaid-svg-P36Zdit0yUz1z8lX .image-shape .label,#mermaid-svg-P36Zdit0yUz1z8lX .icon-shape .label{text-anchor:middle;}#mermaid-svg-P36Zdit0yUz1z8lX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-P36Zdit0yUz1z8lX .rough-node .label,#mermaid-svg-P36Zdit0yUz1z8lX .node .label,#mermaid-svg-P36Zdit0yUz1z8lX .image-shape .label,#mermaid-svg-P36Zdit0yUz1z8lX .icon-shape .label{text-align:center;}#mermaid-svg-P36Zdit0yUz1z8lX .node.clickable{cursor:pointer;}#mermaid-svg-P36Zdit0yUz1z8lX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-P36Zdit0yUz1z8lX .arrowheadPath{fill:#333333;}#mermaid-svg-P36Zdit0yUz1z8lX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-P36Zdit0yUz1z8lX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-P36Zdit0yUz1z8lX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-P36Zdit0yUz1z8lX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-P36Zdit0yUz1z8lX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-P36Zdit0yUz1z8lX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-P36Zdit0yUz1z8lX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-P36Zdit0yUz1z8lX .cluster text{fill:#333;}#mermaid-svg-P36Zdit0yUz1z8lX .cluster span{color:#333;}#mermaid-svg-P36Zdit0yUz1z8lX 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-P36Zdit0yUz1z8lX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-P36Zdit0yUz1z8lX rect.text{fill:none;stroke-width:0;}#mermaid-svg-P36Zdit0yUz1z8lX .icon-shape,#mermaid-svg-P36Zdit0yUz1z8lX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-P36Zdit0yUz1z8lX .icon-shape p,#mermaid-svg-P36Zdit0yUz1z8lX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-P36Zdit0yUz1z8lX .icon-shape .label rect,#mermaid-svg-P36Zdit0yUz1z8lX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-P36Zdit0yUz1z8lX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-P36Zdit0yUz1z8lX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-P36Zdit0yUz1z8lX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 进入 STW
停止所有 G
清空写屏障缓冲区
清扫未完成的 span
finishsweep_m
清空 pools
clearpools
设置 gcphase = _GCmark
启用写屏障
准备 mark worker
准备根对象标记
启动世界
阶段2: 并发标记(Concurrent Mark)
#mermaid-svg-07w9vADVSMMJfCWK{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-07w9vADVSMMJfCWK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-07w9vADVSMMJfCWK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-07w9vADVSMMJfCWK .error-icon{fill:#552222;}#mermaid-svg-07w9vADVSMMJfCWK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-07w9vADVSMMJfCWK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-07w9vADVSMMJfCWK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-07w9vADVSMMJfCWK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-07w9vADVSMMJfCWK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-07w9vADVSMMJfCWK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-07w9vADVSMMJfCWK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-07w9vADVSMMJfCWK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-07w9vADVSMMJfCWK .marker.cross{stroke:#333333;}#mermaid-svg-07w9vADVSMMJfCWK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-07w9vADVSMMJfCWK p{margin:0;}#mermaid-svg-07w9vADVSMMJfCWK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-07w9vADVSMMJfCWK .cluster-label text{fill:#333;}#mermaid-svg-07w9vADVSMMJfCWK .cluster-label span{color:#333;}#mermaid-svg-07w9vADVSMMJfCWK .cluster-label span p{background-color:transparent;}#mermaid-svg-07w9vADVSMMJfCWK .label text,#mermaid-svg-07w9vADVSMMJfCWK span{fill:#333;color:#333;}#mermaid-svg-07w9vADVSMMJfCWK .node rect,#mermaid-svg-07w9vADVSMMJfCWK .node circle,#mermaid-svg-07w9vADVSMMJfCWK .node ellipse,#mermaid-svg-07w9vADVSMMJfCWK .node polygon,#mermaid-svg-07w9vADVSMMJfCWK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-07w9vADVSMMJfCWK .rough-node .label text,#mermaid-svg-07w9vADVSMMJfCWK .node .label text,#mermaid-svg-07w9vADVSMMJfCWK .image-shape .label,#mermaid-svg-07w9vADVSMMJfCWK .icon-shape .label{text-anchor:middle;}#mermaid-svg-07w9vADVSMMJfCWK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-07w9vADVSMMJfCWK .rough-node .label,#mermaid-svg-07w9vADVSMMJfCWK .node .label,#mermaid-svg-07w9vADVSMMJfCWK .image-shape .label,#mermaid-svg-07w9vADVSMMJfCWK .icon-shape .label{text-align:center;}#mermaid-svg-07w9vADVSMMJfCWK .node.clickable{cursor:pointer;}#mermaid-svg-07w9vADVSMMJfCWK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-07w9vADVSMMJfCWK .arrowheadPath{fill:#333333;}#mermaid-svg-07w9vADVSMMJfCWK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-07w9vADVSMMJfCWK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-07w9vADVSMMJfCWK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-07w9vADVSMMJfCWK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-07w9vADVSMMJfCWK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-07w9vADVSMMJfCWK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-07w9vADVSMMJfCWK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-07w9vADVSMMJfCWK .cluster text{fill:#333;}#mermaid-svg-07w9vADVSMMJfCWK .cluster span{color:#333;}#mermaid-svg-07w9vADVSMMJfCWK 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-07w9vADVSMMJfCWK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-07w9vADVSMMJfCWK rect.text{fill:none;stroke-width:0;}#mermaid-svg-07w9vADVSMMJfCWK .icon-shape,#mermaid-svg-07w9vADVSMMJfCWK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-07w9vADVSMMJfCWK .icon-shape p,#mermaid-svg-07w9vADVSMMJfCWK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-07w9vADVSMMJfCWK .icon-shape .label rect,#mermaid-svg-07w9vADVSMMJfCWK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-07w9vADVSMMJfCWK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-07w9vADVSMMJfCWK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-07w9vADVSMMJfCWK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 并发标记
根标记
否
是
是
否
开始并发标记
gcBlackenEnabled = 1
启动 background mark worker
开始根对象标记
扫描栈
扫描全局变量
扫描 finalizer
标记工作协程运行
用户代码协助标记
mutator assist
写屏障保护
工作队列耗尽?
检查完成
gcMarkDone
还有工作?
进入标记终止
阶段3: 标记终止(Mark Termination)- STW
#mermaid-svg-TTp1mM7DXkMMWJGO{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-TTp1mM7DXkMMWJGO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TTp1mM7DXkMMWJGO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TTp1mM7DXkMMWJGO .error-icon{fill:#552222;}#mermaid-svg-TTp1mM7DXkMMWJGO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TTp1mM7DXkMMWJGO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TTp1mM7DXkMMWJGO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TTp1mM7DXkMMWJGO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TTp1mM7DXkMMWJGO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TTp1mM7DXkMMWJGO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TTp1mM7DXkMMWJGO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TTp1mM7DXkMMWJGO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TTp1mM7DXkMMWJGO .marker.cross{stroke:#333333;}#mermaid-svg-TTp1mM7DXkMMWJGO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TTp1mM7DXkMMWJGO p{margin:0;}#mermaid-svg-TTp1mM7DXkMMWJGO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TTp1mM7DXkMMWJGO .cluster-label text{fill:#333;}#mermaid-svg-TTp1mM7DXkMMWJGO .cluster-label span{color:#333;}#mermaid-svg-TTp1mM7DXkMMWJGO .cluster-label span p{background-color:transparent;}#mermaid-svg-TTp1mM7DXkMMWJGO .label text,#mermaid-svg-TTp1mM7DXkMMWJGO span{fill:#333;color:#333;}#mermaid-svg-TTp1mM7DXkMMWJGO .node rect,#mermaid-svg-TTp1mM7DXkMMWJGO .node circle,#mermaid-svg-TTp1mM7DXkMMWJGO .node ellipse,#mermaid-svg-TTp1mM7DXkMMWJGO .node polygon,#mermaid-svg-TTp1mM7DXkMMWJGO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TTp1mM7DXkMMWJGO .rough-node .label text,#mermaid-svg-TTp1mM7DXkMMWJGO .node .label text,#mermaid-svg-TTp1mM7DXkMMWJGO .image-shape .label,#mermaid-svg-TTp1mM7DXkMMWJGO .icon-shape .label{text-anchor:middle;}#mermaid-svg-TTp1mM7DXkMMWJGO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TTp1mM7DXkMMWJGO .rough-node .label,#mermaid-svg-TTp1mM7DXkMMWJGO .node .label,#mermaid-svg-TTp1mM7DXkMMWJGO .image-shape .label,#mermaid-svg-TTp1mM7DXkMMWJGO .icon-shape .label{text-align:center;}#mermaid-svg-TTp1mM7DXkMMWJGO .node.clickable{cursor:pointer;}#mermaid-svg-TTp1mM7DXkMMWJGO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TTp1mM7DXkMMWJGO .arrowheadPath{fill:#333333;}#mermaid-svg-TTp1mM7DXkMMWJGO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TTp1mM7DXkMMWJGO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TTp1mM7DXkMMWJGO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TTp1mM7DXkMMWJGO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TTp1mM7DXkMMWJGO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TTp1mM7DXkMMWJGO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TTp1mM7DXkMMWJGO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TTp1mM7DXkMMWJGO .cluster text{fill:#333;}#mermaid-svg-TTp1mM7DXkMMWJGO .cluster span{color:#333;}#mermaid-svg-TTp1mM7DXkMMWJGO 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-TTp1mM7DXkMMWJGO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TTp1mM7DXkMMWJGO rect.text{fill:none;stroke-width:0;}#mermaid-svg-TTp1mM7DXkMMWJGO .icon-shape,#mermaid-svg-TTp1mM7DXkMMWJGO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TTp1mM7DXkMMWJGO .icon-shape p,#mermaid-svg-TTp1mM7DXkMMWJGO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TTp1mM7DXkMMWJGO .icon-shape .label rect,#mermaid-svg-TTp1mM7DXkMMWJGO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TTp1mM7DXkMMWJGO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TTp1mM7DXkMMWJGO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TTp1mM7DXkMMWJGO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 进入 STW
停止所有 G
gcBlackenEnabled = 0
清空写屏障缓冲区
完成剩余标记工作
执行 mark termination
设置 gcphase = _GCoff
禁用写屏障
更新 GC 统计
更新 pacing
准备清扫
启动世界
阶段4: 并发清扫(Concurrent Sweep)
#mermaid-svg-C00yHgi9ahcNqdCn{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-C00yHgi9ahcNqdCn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-C00yHgi9ahcNqdCn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-C00yHgi9ahcNqdCn .error-icon{fill:#552222;}#mermaid-svg-C00yHgi9ahcNqdCn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-C00yHgi9ahcNqdCn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-C00yHgi9ahcNqdCn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-C00yHgi9ahcNqdCn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-C00yHgi9ahcNqdCn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-C00yHgi9ahcNqdCn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-C00yHgi9ahcNqdCn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-C00yHgi9ahcNqdCn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-C00yHgi9ahcNqdCn .marker.cross{stroke:#333333;}#mermaid-svg-C00yHgi9ahcNqdCn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-C00yHgi9ahcNqdCn p{margin:0;}#mermaid-svg-C00yHgi9ahcNqdCn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-C00yHgi9ahcNqdCn .cluster-label text{fill:#333;}#mermaid-svg-C00yHgi9ahcNqdCn .cluster-label span{color:#333;}#mermaid-svg-C00yHgi9ahcNqdCn .cluster-label span p{background-color:transparent;}#mermaid-svg-C00yHgi9ahcNqdCn .label text,#mermaid-svg-C00yHgi9ahcNqdCn span{fill:#333;color:#333;}#mermaid-svg-C00yHgi9ahcNqdCn .node rect,#mermaid-svg-C00yHgi9ahcNqdCn .node circle,#mermaid-svg-C00yHgi9ahcNqdCn .node ellipse,#mermaid-svg-C00yHgi9ahcNqdCn .node polygon,#mermaid-svg-C00yHgi9ahcNqdCn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-C00yHgi9ahcNqdCn .rough-node .label text,#mermaid-svg-C00yHgi9ahcNqdCn .node .label text,#mermaid-svg-C00yHgi9ahcNqdCn .image-shape .label,#mermaid-svg-C00yHgi9ahcNqdCn .icon-shape .label{text-anchor:middle;}#mermaid-svg-C00yHgi9ahcNqdCn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-C00yHgi9ahcNqdCn .rough-node .label,#mermaid-svg-C00yHgi9ahcNqdCn .node .label,#mermaid-svg-C00yHgi9ahcNqdCn .image-shape .label,#mermaid-svg-C00yHgi9ahcNqdCn .icon-shape .label{text-align:center;}#mermaid-svg-C00yHgi9ahcNqdCn .node.clickable{cursor:pointer;}#mermaid-svg-C00yHgi9ahcNqdCn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-C00yHgi9ahcNqdCn .arrowheadPath{fill:#333333;}#mermaid-svg-C00yHgi9ahcNqdCn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-C00yHgi9ahcNqdCn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-C00yHgi9ahcNqdCn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C00yHgi9ahcNqdCn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-C00yHgi9ahcNqdCn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C00yHgi9ahcNqdCn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-C00yHgi9ahcNqdCn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-C00yHgi9ahcNqdCn .cluster text{fill:#333;}#mermaid-svg-C00yHgi9ahcNqdCn .cluster span{color:#333;}#mermaid-svg-C00yHgi9ahcNqdCn 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-C00yHgi9ahcNqdCn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-C00yHgi9ahcNqdCn rect.text{fill:none;stroke-width:0;}#mermaid-svg-C00yHgi9ahcNqdCn .icon-shape,#mermaid-svg-C00yHgi9ahcNqdCn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C00yHgi9ahcNqdCn .icon-shape p,#mermaid-svg-C00yHgi9ahcNqdCn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-C00yHgi9ahcNqdCn .icon-shape .label rect,#mermaid-svg-C00yHgi9ahcNqdCn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C00yHgi9ahcNqdCn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-C00yHgi9ahcNqdCn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-C00yHgi9ahcNqdCn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} sweepone
开始并发清扫
后台 sweeper 运行
bgsweep
分配时按需清扫
on-demand sweep
获取下一个 span
检查 sweepgen
清理标记位
释放未标记对象
归还页给堆
3.5 STW 产生时机与性能影响
源码位置 :src/runtime/proc.go 的 stopTheWorldWithSema
#mermaid-svg-2y1uynqLpB6forEp{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-2y1uynqLpB6forEp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2y1uynqLpB6forEp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2y1uynqLpB6forEp .error-icon{fill:#552222;}#mermaid-svg-2y1uynqLpB6forEp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2y1uynqLpB6forEp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2y1uynqLpB6forEp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2y1uynqLpB6forEp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2y1uynqLpB6forEp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2y1uynqLpB6forEp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2y1uynqLpB6forEp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2y1uynqLpB6forEp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2y1uynqLpB6forEp .marker.cross{stroke:#333333;}#mermaid-svg-2y1uynqLpB6forEp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2y1uynqLpB6forEp p{margin:0;}#mermaid-svg-2y1uynqLpB6forEp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2y1uynqLpB6forEp .cluster-label text{fill:#333;}#mermaid-svg-2y1uynqLpB6forEp .cluster-label span{color:#333;}#mermaid-svg-2y1uynqLpB6forEp .cluster-label span p{background-color:transparent;}#mermaid-svg-2y1uynqLpB6forEp .label text,#mermaid-svg-2y1uynqLpB6forEp span{fill:#333;color:#333;}#mermaid-svg-2y1uynqLpB6forEp .node rect,#mermaid-svg-2y1uynqLpB6forEp .node circle,#mermaid-svg-2y1uynqLpB6forEp .node ellipse,#mermaid-svg-2y1uynqLpB6forEp .node polygon,#mermaid-svg-2y1uynqLpB6forEp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2y1uynqLpB6forEp .rough-node .label text,#mermaid-svg-2y1uynqLpB6forEp .node .label text,#mermaid-svg-2y1uynqLpB6forEp .image-shape .label,#mermaid-svg-2y1uynqLpB6forEp .icon-shape .label{text-anchor:middle;}#mermaid-svg-2y1uynqLpB6forEp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2y1uynqLpB6forEp .rough-node .label,#mermaid-svg-2y1uynqLpB6forEp .node .label,#mermaid-svg-2y1uynqLpB6forEp .image-shape .label,#mermaid-svg-2y1uynqLpB6forEp .icon-shape .label{text-align:center;}#mermaid-svg-2y1uynqLpB6forEp .node.clickable{cursor:pointer;}#mermaid-svg-2y1uynqLpB6forEp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2y1uynqLpB6forEp .arrowheadPath{fill:#333333;}#mermaid-svg-2y1uynqLpB6forEp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2y1uynqLpB6forEp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2y1uynqLpB6forEp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2y1uynqLpB6forEp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2y1uynqLpB6forEp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2y1uynqLpB6forEp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2y1uynqLpB6forEp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2y1uynqLpB6forEp .cluster text{fill:#333;}#mermaid-svg-2y1uynqLpB6forEp .cluster span{color:#333;}#mermaid-svg-2y1uynqLpB6forEp 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-2y1uynqLpB6forEp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2y1uynqLpB6forEp rect.text{fill:none;stroke-width:0;}#mermaid-svg-2y1uynqLpB6forEp .icon-shape,#mermaid-svg-2y1uynqLpB6forEp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2y1uynqLpB6forEp .icon-shape p,#mermaid-svg-2y1uynqLpB6forEp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2y1uynqLpB6forEp .icon-shape .label rect,#mermaid-svg-2y1uynqLpB6forEp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2y1uynqLpB6forEp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2y1uynqLpB6forEp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2y1uynqLpB6forEp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} STW 做什么
STW 触发点
标记预备阶段
sweep termination
标记终止阶段
mark termination
停止所有 P
停止所有 G 在安全点
后台任务清理
STW 时间统计(典型值):
| 阶段 | 典型时间 | 主要工作 |
|---|---|---|
| 标记预备 | 10-50 µs | 清空缓冲区、清扫残余 |
| 标记终止 | 100-500 µs | 完成标记、更新统计 |
优化手段:
- 安全点轮询:在函数序言和循环回边插入检查
- 异步停止:不需要立即停止所有 G
- 减少工作量:把尽量多的工作移到并发阶段
3.6 GC Pacer 与触发机制
源码位置 :src/runtime/mgcpacer.go
#mermaid-svg-YK7fIhIwGVImEMv6{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-YK7fIhIwGVImEMv6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YK7fIhIwGVImEMv6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YK7fIhIwGVImEMv6 .error-icon{fill:#552222;}#mermaid-svg-YK7fIhIwGVImEMv6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YK7fIhIwGVImEMv6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YK7fIhIwGVImEMv6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YK7fIhIwGVImEMv6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YK7fIhIwGVImEMv6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YK7fIhIwGVImEMv6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YK7fIhIwGVImEMv6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YK7fIhIwGVImEMv6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YK7fIhIwGVImEMv6 .marker.cross{stroke:#333333;}#mermaid-svg-YK7fIhIwGVImEMv6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YK7fIhIwGVImEMv6 p{margin:0;}#mermaid-svg-YK7fIhIwGVImEMv6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YK7fIhIwGVImEMv6 .cluster-label text{fill:#333;}#mermaid-svg-YK7fIhIwGVImEMv6 .cluster-label span{color:#333;}#mermaid-svg-YK7fIhIwGVImEMv6 .cluster-label span p{background-color:transparent;}#mermaid-svg-YK7fIhIwGVImEMv6 .label text,#mermaid-svg-YK7fIhIwGVImEMv6 span{fill:#333;color:#333;}#mermaid-svg-YK7fIhIwGVImEMv6 .node rect,#mermaid-svg-YK7fIhIwGVImEMv6 .node circle,#mermaid-svg-YK7fIhIwGVImEMv6 .node ellipse,#mermaid-svg-YK7fIhIwGVImEMv6 .node polygon,#mermaid-svg-YK7fIhIwGVImEMv6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YK7fIhIwGVImEMv6 .rough-node .label text,#mermaid-svg-YK7fIhIwGVImEMv6 .node .label text,#mermaid-svg-YK7fIhIwGVImEMv6 .image-shape .label,#mermaid-svg-YK7fIhIwGVImEMv6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-YK7fIhIwGVImEMv6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YK7fIhIwGVImEMv6 .rough-node .label,#mermaid-svg-YK7fIhIwGVImEMv6 .node .label,#mermaid-svg-YK7fIhIwGVImEMv6 .image-shape .label,#mermaid-svg-YK7fIhIwGVImEMv6 .icon-shape .label{text-align:center;}#mermaid-svg-YK7fIhIwGVImEMv6 .node.clickable{cursor:pointer;}#mermaid-svg-YK7fIhIwGVImEMv6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YK7fIhIwGVImEMv6 .arrowheadPath{fill:#333333;}#mermaid-svg-YK7fIhIwGVImEMv6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YK7fIhIwGVImEMv6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YK7fIhIwGVImEMv6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YK7fIhIwGVImEMv6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YK7fIhIwGVImEMv6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YK7fIhIwGVImEMv6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YK7fIhIwGVImEMv6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YK7fIhIwGVImEMv6 .cluster text{fill:#333;}#mermaid-svg-YK7fIhIwGVImEMv6 .cluster span{color:#333;}#mermaid-svg-YK7fIhIwGVImEMv6 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-YK7fIhIwGVImEMv6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YK7fIhIwGVImEMv6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-YK7fIhIwGVImEMv6 .icon-shape,#mermaid-svg-YK7fIhIwGVImEMv6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YK7fIhIwGVImEMv6 .icon-shape p,#mermaid-svg-YK7fIhIwGVImEMv6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YK7fIhIwGVImEMv6 .icon-shape .label rect,#mermaid-svg-YK7fIhIwGVImEMv6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YK7fIhIwGVImEMv6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YK7fIhIwGVImEMv6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YK7fIhIwGVImEMv6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Pacer 计算
GC 触发条件
堆大小阈值
heapLive >= heapGoal
时间阈值
forcegcperiod
手动触发
runtime.GC()
GOGC (default 100)
heapLive
heapGoal = heapMarked + (heapMarked * GOGC / 100)
核心公式:
heapGoal = heapMarked * (1 + GOGC/100) + heapMarked
触发场景:
-
堆阈值触发:
goif gcphase == _GCoff && gcController.heapLive.Load() >= gcController.trigger { gcStart(gcTrigger{kind: gcTriggerHeap}) } -
时间触发(默认 2 分钟):
goif gcphase == _GCoff && now-lastGC > forcegcperiod { gcStart(gcTrigger{kind: gcTriggerTime}) } -
手动触发:
gofunc GC() { gcStart(gcTrigger{kind: gcTriggerCycle}) }
3.7 GC 与 M/P/G 调度协同
源码位置 :src/runtime/mgc.go 的 gcBgMarkWorker
#mermaid-svg-X8oA6Q8pN3gMqpll{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-X8oA6Q8pN3gMqpll .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-X8oA6Q8pN3gMqpll .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-X8oA6Q8pN3gMqpll .error-icon{fill:#552222;}#mermaid-svg-X8oA6Q8pN3gMqpll .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-X8oA6Q8pN3gMqpll .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-X8oA6Q8pN3gMqpll .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-X8oA6Q8pN3gMqpll .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-X8oA6Q8pN3gMqpll .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-X8oA6Q8pN3gMqpll .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-X8oA6Q8pN3gMqpll .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-X8oA6Q8pN3gMqpll .marker{fill:#333333;stroke:#333333;}#mermaid-svg-X8oA6Q8pN3gMqpll .marker.cross{stroke:#333333;}#mermaid-svg-X8oA6Q8pN3gMqpll svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-X8oA6Q8pN3gMqpll p{margin:0;}#mermaid-svg-X8oA6Q8pN3gMqpll .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-X8oA6Q8pN3gMqpll .cluster-label text{fill:#333;}#mermaid-svg-X8oA6Q8pN3gMqpll .cluster-label span{color:#333;}#mermaid-svg-X8oA6Q8pN3gMqpll .cluster-label span p{background-color:transparent;}#mermaid-svg-X8oA6Q8pN3gMqpll .label text,#mermaid-svg-X8oA6Q8pN3gMqpll span{fill:#333;color:#333;}#mermaid-svg-X8oA6Q8pN3gMqpll .node rect,#mermaid-svg-X8oA6Q8pN3gMqpll .node circle,#mermaid-svg-X8oA6Q8pN3gMqpll .node ellipse,#mermaid-svg-X8oA6Q8pN3gMqpll .node polygon,#mermaid-svg-X8oA6Q8pN3gMqpll .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-X8oA6Q8pN3gMqpll .rough-node .label text,#mermaid-svg-X8oA6Q8pN3gMqpll .node .label text,#mermaid-svg-X8oA6Q8pN3gMqpll .image-shape .label,#mermaid-svg-X8oA6Q8pN3gMqpll .icon-shape .label{text-anchor:middle;}#mermaid-svg-X8oA6Q8pN3gMqpll .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-X8oA6Q8pN3gMqpll .rough-node .label,#mermaid-svg-X8oA6Q8pN3gMqpll .node .label,#mermaid-svg-X8oA6Q8pN3gMqpll .image-shape .label,#mermaid-svg-X8oA6Q8pN3gMqpll .icon-shape .label{text-align:center;}#mermaid-svg-X8oA6Q8pN3gMqpll .node.clickable{cursor:pointer;}#mermaid-svg-X8oA6Q8pN3gMqpll .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-X8oA6Q8pN3gMqpll .arrowheadPath{fill:#333333;}#mermaid-svg-X8oA6Q8pN3gMqpll .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-X8oA6Q8pN3gMqpll .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-X8oA6Q8pN3gMqpll .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X8oA6Q8pN3gMqpll .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-X8oA6Q8pN3gMqpll .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X8oA6Q8pN3gMqpll .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-X8oA6Q8pN3gMqpll .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-X8oA6Q8pN3gMqpll .cluster text{fill:#333;}#mermaid-svg-X8oA6Q8pN3gMqpll .cluster span{color:#333;}#mermaid-svg-X8oA6Q8pN3gMqpll 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-X8oA6Q8pN3gMqpll .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-X8oA6Q8pN3gMqpll rect.text{fill:none;stroke-width:0;}#mermaid-svg-X8oA6Q8pN3gMqpll .icon-shape,#mermaid-svg-X8oA6Q8pN3gMqpll .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X8oA6Q8pN3gMqpll .icon-shape p,#mermaid-svg-X8oA6Q8pN3gMqpll .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-X8oA6Q8pN3gMqpll .icon-shape .label rect,#mermaid-svg-X8oA6Q8pN3gMqpll .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X8oA6Q8pN3gMqpll .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-X8oA6Q8pN3gMqpll .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-X8oA6Q8pN3gMqpll :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GOMAXPROCS 分配
调度模式
Dedicated Mode
专用模式
不被抢占
Fractional Mode
部分模式
按时间片
Idle Mode
空闲模式
P 空闲时运行
GC 使用 25% CPU
(最多 1 个专用 P)
用户代码 使用 75%+ CPU
Mark Worker 模式:
-
Dedicated Mode:
- 专门用于 GC
- 不会被抢占
- 最多一个 P
-
Fractional Mode:
- 部分时间用于 GC
- 按照时间片调度
-
Idle Mode:
- 仅在 P 空闲时运行
- 有工作时立即让出
3.8 并发清扫与内存归还
源码位置 :src/runtime/mgcsweep.go
#mermaid-svg-5GBl0hTH42mRrMaU{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-5GBl0hTH42mRrMaU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5GBl0hTH42mRrMaU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5GBl0hTH42mRrMaU .error-icon{fill:#552222;}#mermaid-svg-5GBl0hTH42mRrMaU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5GBl0hTH42mRrMaU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5GBl0hTH42mRrMaU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5GBl0hTH42mRrMaU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5GBl0hTH42mRrMaU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5GBl0hTH42mRrMaU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5GBl0hTH42mRrMaU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5GBl0hTH42mRrMaU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5GBl0hTH42mRrMaU .marker.cross{stroke:#333333;}#mermaid-svg-5GBl0hTH42mRrMaU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5GBl0hTH42mRrMaU p{margin:0;}#mermaid-svg-5GBl0hTH42mRrMaU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5GBl0hTH42mRrMaU .cluster-label text{fill:#333;}#mermaid-svg-5GBl0hTH42mRrMaU .cluster-label span{color:#333;}#mermaid-svg-5GBl0hTH42mRrMaU .cluster-label span p{background-color:transparent;}#mermaid-svg-5GBl0hTH42mRrMaU .label text,#mermaid-svg-5GBl0hTH42mRrMaU span{fill:#333;color:#333;}#mermaid-svg-5GBl0hTH42mRrMaU .node rect,#mermaid-svg-5GBl0hTH42mRrMaU .node circle,#mermaid-svg-5GBl0hTH42mRrMaU .node ellipse,#mermaid-svg-5GBl0hTH42mRrMaU .node polygon,#mermaid-svg-5GBl0hTH42mRrMaU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5GBl0hTH42mRrMaU .rough-node .label text,#mermaid-svg-5GBl0hTH42mRrMaU .node .label text,#mermaid-svg-5GBl0hTH42mRrMaU .image-shape .label,#mermaid-svg-5GBl0hTH42mRrMaU .icon-shape .label{text-anchor:middle;}#mermaid-svg-5GBl0hTH42mRrMaU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5GBl0hTH42mRrMaU .rough-node .label,#mermaid-svg-5GBl0hTH42mRrMaU .node .label,#mermaid-svg-5GBl0hTH42mRrMaU .image-shape .label,#mermaid-svg-5GBl0hTH42mRrMaU .icon-shape .label{text-align:center;}#mermaid-svg-5GBl0hTH42mRrMaU .node.clickable{cursor:pointer;}#mermaid-svg-5GBl0hTH42mRrMaU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5GBl0hTH42mRrMaU .arrowheadPath{fill:#333333;}#mermaid-svg-5GBl0hTH42mRrMaU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5GBl0hTH42mRrMaU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5GBl0hTH42mRrMaU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5GBl0hTH42mRrMaU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5GBl0hTH42mRrMaU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5GBl0hTH42mRrMaU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5GBl0hTH42mRrMaU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5GBl0hTH42mRrMaU .cluster text{fill:#333;}#mermaid-svg-5GBl0hTH42mRrMaU .cluster span{color:#333;}#mermaid-svg-5GBl0hTH42mRrMaU 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-5GBl0hTH42mRrMaU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5GBl0hTH42mRrMaU rect.text{fill:none;stroke-width:0;}#mermaid-svg-5GBl0hTH42mRrMaU .icon-shape,#mermaid-svg-5GBl0hTH42mRrMaU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5GBl0hTH42mRrMaU .icon-shape p,#mermaid-svg-5GBl0hTH42mRrMaU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5GBl0hTH42mRrMaU .icon-shape .label rect,#mermaid-svg-5GBl0hTH42mRrMaU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5GBl0hTH42mRrMaU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5GBl0hTH42mRrMaU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5GBl0hTH42mRrMaU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
是
否
是
否
sweepone 调用
找到 span?
返回 ^uintptr(0)
检查 sweepgen
需要清扫?
跳过
重置 allocBits
扫描 gcmarkBits
对象被标记?
设置 allocBits 位
对象空闲
更新统计
添加到 freelist
span 全空?
归还页给 heap
添加到 mcentral
可能归还 OS
scavenge
后台清扫(bgsweep):
go
func bgsweep(c chan int) {
// ...
for {
// 清扫一些 span
for sweepone() != ^uintptr(0) {
// ...
}
// 休眠等待
goparkunlock(...)
}
}
3.9 内存回收与归还操作系统
源码位置 :src/runtime/mgcscavenge.go
#mermaid-svg-PuKrRgai7FhIVSu7{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-PuKrRgai7FhIVSu7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PuKrRgai7FhIVSu7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PuKrRgai7FhIVSu7 .error-icon{fill:#552222;}#mermaid-svg-PuKrRgai7FhIVSu7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PuKrRgai7FhIVSu7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PuKrRgai7FhIVSu7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PuKrRgai7FhIVSu7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PuKrRgai7FhIVSu7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PuKrRgai7FhIVSu7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PuKrRgai7FhIVSu7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PuKrRgai7FhIVSu7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PuKrRgai7FhIVSu7 .marker.cross{stroke:#333333;}#mermaid-svg-PuKrRgai7FhIVSu7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PuKrRgai7FhIVSu7 p{margin:0;}#mermaid-svg-PuKrRgai7FhIVSu7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PuKrRgai7FhIVSu7 .cluster-label text{fill:#333;}#mermaid-svg-PuKrRgai7FhIVSu7 .cluster-label span{color:#333;}#mermaid-svg-PuKrRgai7FhIVSu7 .cluster-label span p{background-color:transparent;}#mermaid-svg-PuKrRgai7FhIVSu7 .label text,#mermaid-svg-PuKrRgai7FhIVSu7 span{fill:#333;color:#333;}#mermaid-svg-PuKrRgai7FhIVSu7 .node rect,#mermaid-svg-PuKrRgai7FhIVSu7 .node circle,#mermaid-svg-PuKrRgai7FhIVSu7 .node ellipse,#mermaid-svg-PuKrRgai7FhIVSu7 .node polygon,#mermaid-svg-PuKrRgai7FhIVSu7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PuKrRgai7FhIVSu7 .rough-node .label text,#mermaid-svg-PuKrRgai7FhIVSu7 .node .label text,#mermaid-svg-PuKrRgai7FhIVSu7 .image-shape .label,#mermaid-svg-PuKrRgai7FhIVSu7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-PuKrRgai7FhIVSu7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PuKrRgai7FhIVSu7 .rough-node .label,#mermaid-svg-PuKrRgai7FhIVSu7 .node .label,#mermaid-svg-PuKrRgai7FhIVSu7 .image-shape .label,#mermaid-svg-PuKrRgai7FhIVSu7 .icon-shape .label{text-align:center;}#mermaid-svg-PuKrRgai7FhIVSu7 .node.clickable{cursor:pointer;}#mermaid-svg-PuKrRgai7FhIVSu7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PuKrRgai7FhIVSu7 .arrowheadPath{fill:#333333;}#mermaid-svg-PuKrRgai7FhIVSu7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PuKrRgai7FhIVSu7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PuKrRgai7FhIVSu7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PuKrRgai7FhIVSu7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PuKrRgai7FhIVSu7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PuKrRgai7FhIVSu7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PuKrRgai7FhIVSu7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PuKrRgai7FhIVSu7 .cluster text{fill:#333;}#mermaid-svg-PuKrRgai7FhIVSu7 .cluster span{color:#333;}#mermaid-svg-PuKrRgai7FhIVSu7 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-PuKrRgai7FhIVSu7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PuKrRgai7FhIVSu7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-PuKrRgai7FhIVSu7 .icon-shape,#mermaid-svg-PuKrRgai7FhIVSu7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PuKrRgai7FhIVSu7 .icon-shape p,#mermaid-svg-PuKrRgai7FhIVSu7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PuKrRgai7FhIVSu7 .icon-shape .label rect,#mermaid-svg-PuKrRgai7FhIVSu7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PuKrRgai7FhIVSu7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PuKrRgai7FhIVSu7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PuKrRgai7FhIVSu7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 策略
Scavenger
Background Scavenger
后台回收器
目标:返还未使用内存
给操作系统
Scavenge Assist
分配时协助回收
Lazy Scavenging
延迟回收:按需回收
Eager Scavenging
激进回收:GC 后立即回收
scavenge 目标:
- 保持
heapInUse/heapReleased在合理比例 - 在 GC 后激进回收
- 在内存压力大时协助回收
3.10 大对象与 finalizer 处理
大对象处理:
- 大对象直接作为一个 span 分配
- 不需要 size class
- 标记时直接扫描整个对象
Finalizer 处理:
#mermaid-svg-S72tl0T15LOAcPaF{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-S72tl0T15LOAcPaF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-S72tl0T15LOAcPaF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-S72tl0T15LOAcPaF .error-icon{fill:#552222;}#mermaid-svg-S72tl0T15LOAcPaF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-S72tl0T15LOAcPaF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-S72tl0T15LOAcPaF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-S72tl0T15LOAcPaF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-S72tl0T15LOAcPaF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-S72tl0T15LOAcPaF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-S72tl0T15LOAcPaF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-S72tl0T15LOAcPaF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-S72tl0T15LOAcPaF .marker.cross{stroke:#333333;}#mermaid-svg-S72tl0T15LOAcPaF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-S72tl0T15LOAcPaF p{margin:0;}#mermaid-svg-S72tl0T15LOAcPaF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-S72tl0T15LOAcPaF .cluster-label text{fill:#333;}#mermaid-svg-S72tl0T15LOAcPaF .cluster-label span{color:#333;}#mermaid-svg-S72tl0T15LOAcPaF .cluster-label span p{background-color:transparent;}#mermaid-svg-S72tl0T15LOAcPaF .label text,#mermaid-svg-S72tl0T15LOAcPaF span{fill:#333;color:#333;}#mermaid-svg-S72tl0T15LOAcPaF .node rect,#mermaid-svg-S72tl0T15LOAcPaF .node circle,#mermaid-svg-S72tl0T15LOAcPaF .node ellipse,#mermaid-svg-S72tl0T15LOAcPaF .node polygon,#mermaid-svg-S72tl0T15LOAcPaF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-S72tl0T15LOAcPaF .rough-node .label text,#mermaid-svg-S72tl0T15LOAcPaF .node .label text,#mermaid-svg-S72tl0T15LOAcPaF .image-shape .label,#mermaid-svg-S72tl0T15LOAcPaF .icon-shape .label{text-anchor:middle;}#mermaid-svg-S72tl0T15LOAcPaF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-S72tl0T15LOAcPaF .rough-node .label,#mermaid-svg-S72tl0T15LOAcPaF .node .label,#mermaid-svg-S72tl0T15LOAcPaF .image-shape .label,#mermaid-svg-S72tl0T15LOAcPaF .icon-shape .label{text-align:center;}#mermaid-svg-S72tl0T15LOAcPaF .node.clickable{cursor:pointer;}#mermaid-svg-S72tl0T15LOAcPaF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-S72tl0T15LOAcPaF .arrowheadPath{fill:#333333;}#mermaid-svg-S72tl0T15LOAcPaF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-S72tl0T15LOAcPaF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-S72tl0T15LOAcPaF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-S72tl0T15LOAcPaF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-S72tl0T15LOAcPaF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-S72tl0T15LOAcPaF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-S72tl0T15LOAcPaF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-S72tl0T15LOAcPaF .cluster text{fill:#333;}#mermaid-svg-S72tl0T15LOAcPaF .cluster span{color:#333;}#mermaid-svg-S72tl0T15LOAcPaF 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-S72tl0T15LOAcPaF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-S72tl0T15LOAcPaF rect.text{fill:none;stroke-width:0;}#mermaid-svg-S72tl0T15LOAcPaF .icon-shape,#mermaid-svg-S72tl0T15LOAcPaF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-S72tl0T15LOAcPaF .icon-shape p,#mermaid-svg-S72tl0T15LOAcPaF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-S72tl0T15LOAcPaF .icon-shape .label rect,#mermaid-svg-S72tl0T15LOAcPaF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-S72tl0T15LOAcPaF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-S72tl0T15LOAcPaF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-S72tl0T15LOAcPaF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 对象有 finalizer
对象不可达
加入 finalizer 队列
唤醒 finalizer G
执行 finalizer
下一次 GC 回收对象
3.11 写屏障原理图
GC Worker Write Barrier Mutator (用户代码) GC Worker Write Barrier Mutator (用户代码) #mermaid-svg-gAUyS6jyOY2ajo6P{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-gAUyS6jyOY2ajo6P .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gAUyS6jyOY2ajo6P .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gAUyS6jyOY2ajo6P .error-icon{fill:#552222;}#mermaid-svg-gAUyS6jyOY2ajo6P .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gAUyS6jyOY2ajo6P .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gAUyS6jyOY2ajo6P .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gAUyS6jyOY2ajo6P .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gAUyS6jyOY2ajo6P .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gAUyS6jyOY2ajo6P .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gAUyS6jyOY2ajo6P .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gAUyS6jyOY2ajo6P .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gAUyS6jyOY2ajo6P .marker.cross{stroke:#333333;}#mermaid-svg-gAUyS6jyOY2ajo6P svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gAUyS6jyOY2ajo6P p{margin:0;}#mermaid-svg-gAUyS6jyOY2ajo6P .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gAUyS6jyOY2ajo6P text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-gAUyS6jyOY2ajo6P .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gAUyS6jyOY2ajo6P .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-gAUyS6jyOY2ajo6P .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-gAUyS6jyOY2ajo6P .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-gAUyS6jyOY2ajo6P #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-gAUyS6jyOY2ajo6P .sequenceNumber{fill:white;}#mermaid-svg-gAUyS6jyOY2ajo6P #sequencenumber{fill:#333;}#mermaid-svg-gAUyS6jyOY2ajo6P #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-gAUyS6jyOY2ajo6P .messageText{fill:#333;stroke:none;}#mermaid-svg-gAUyS6jyOY2ajo6P .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gAUyS6jyOY2ajo6P .labelText,#mermaid-svg-gAUyS6jyOY2ajo6P .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-gAUyS6jyOY2ajo6P .loopText,#mermaid-svg-gAUyS6jyOY2ajo6P .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-gAUyS6jyOY2ajo6P .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-gAUyS6jyOY2ajo6P .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-gAUyS6jyOY2ajo6P .noteText,#mermaid-svg-gAUyS6jyOY2ajo6P .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-gAUyS6jyOY2ajo6P .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gAUyS6jyOY2ajo6P .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gAUyS6jyOY2ajo6P .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gAUyS6jyOY2ajo6P .actorPopupMenu{position:absolute;}#mermaid-svg-gAUyS6jyOY2ajo6P .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-gAUyS6jyOY2ajo6P .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gAUyS6jyOY2ajo6P .actor-man circle,#mermaid-svg-gAUyS6jyOY2ajo6P line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-gAUyS6jyOY2ajo6P :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 写屏障执行 alt ptr 是白色 alt \*slot 是白色 三色不变性保持 *slot = ptr shade(ptr) 将 ptr 标记为灰色 shade(*slot) 将 *slot 标记为灰色 完成写入
3.12 STW 触发场景对比图
| 触发点 | 阶段 | 典型耗时 | 为什么需要 STW |
|---|---|---|---|
| 标记预备 | GC 开始 | 10-50 µs | 启用写屏障、完成上一轮清扫 |
| 标记终止 | GC 结束 | 100-500 µs | 完成最终标记、计算下一次目标 |
4. Runtime 关键源码逐段解析
4.1 mallocgc - 对象分配入口
源码位置 :src/runtime/malloc.go
go
// 分配大小为 size 的对象
// 如果需要清零,nil 会被清零
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
// ... 省略部分代码 ...
// --------------- 阶段 1: 检查和准备 ---------------
// 获取当前 mcache
mp := acquirem()
mp.mallocing = 1
c := getMCache(mp)
if c == nil {
throw("mallocgc called without a P or outside bootstrapping")
}
// --------------- 阶段 2: 微对象分配 ---------------
// 如果是小对象且无指针,尝试微分配
if size <= maxTinySize && typ == nil {
// 微对象分配器
// ...
}
// --------------- 阶段 3: 计算大小类 ---------------
var sizeclass uint8
var npages uintptr
var span *mspan
// 小对象:使用 size class
if size <= maxSmallSize {
if size < smallSizeMax-8 {
sizeclass = size_to_class8[divRoundUp(size, smallSizeDiv)]
} else {
sizeclass = size_to_class128[divRoundUp(size-smallSizeMax, largeSizeDiv)]
}
size = uintptr(class_to_size[sizeclass])
spc := makeSpanClass(sizeclass, noscan)
// --------------- 阶段 4: 从 mcache 分配 ---------------
span = c.alloc[spc]
// ...
} else {
// --------------- 阶段 5: 大对象分配 ---------------
npages = size >> pageShift
if size&pageMask != 0 {
npages++
}
// ...
}
// --------------- 阶段 6: 返回对象 ---------------
mp.mallocing = 0
releasem(mp)
return unsafe.Pointer(x)
}
4.2 mcache.refill - 补充 span
源码位置 :src/runtime/mcache.go
go
// refill 获取一个新的 span 到 mcache
func (c *mcache) refill(spc spanClass) {
// 返回当前 span 到 central
s := c.alloc[spc]
if s != &emptymspan {
// 标记 span 不再被缓存
if s.sweepgen != mheap_.sweepgen+3 {
throw("bad sweepgen in refill")
}
mheap_.central[spc].mcentral.uncacheSpan(s)
}
// 从 central 获取新 span
s = mheap_.central[spc].mcentral.cacheSpan()
if s == nil {
throw("out of memory")
}
// 标记 span 被缓存
s.sweepgen = mheap_.sweepgen + 3
c.alloc[spc] = s
}
4.3 mcentral.cacheSpan - 获取 span
源码位置 :src/runtime/mcentral.go
go
// cacheSpan 从 mcentral 获取一个可用的 span
func (c *mcentral) cacheSpan() *mspan {
// 扣除清扫信用
spanBytes := uintptr(class_to_allocnpages[c.spanclass.sizeclass()]) * pageSize
deductSweepCredit(spanBytes, 0)
// --------------- 1. 先尝试已清扫的 partial span ---------------
sg := mheap_.sweepgen
if s := c.partialSwept(sg).pop(); s != nil {
return s
}
// --------------- 2. 尝试未清扫的 span ---------------
sl := sweep.active.begin()
if sl.valid {
spanBudget := 100
// 尝试 partial unswept
for ; spanBudget >= 0; spanBudget-- {
s := c.partialUnswept(sg).pop()
if s == nil {
break
}
if s, ok := sl.tryAcquire(s); ok {
s.sweep(true)
sweep.active.end(sl)
return s
}
}
// 尝试 full unswept
for ; spanBudget >= 0; spanBudget-- {
s := c.fullUnswept(sg).pop()
if s == nil {
break
}
if s, ok := sl.tryAcquire(s); ok {
s.sweep(true)
freeIndex := s.nextFreeIndex()
if freeIndex != s.nelems {
s.freeindex = freeIndex
sweep.active.end(sl)
return s
}
c.fullSwept(sg).push(s.mspan)
}
}
sweep.active.end(sl)
}
// --------------- 3. 都没找到,从 heap 分配新 span ---------------
return c.grow()
}
4.4 mheap.alloc - 从堆分配
源码位置 :src/runtime/mheap.go
go
// 从堆分配 npages 页的 span
func (h *mheap) alloc(npages uintptr, spanclass spanClass) *mspan {
// ...
systemstack(func() {
// 加锁
lock(&h.lock)
// 从 pageAlloc 分配
v, s := h.pages.alloc(npages)
if v == 0 {
// 分配失败,尝试增长堆
// ...
}
// 初始化 span
s.init(v, npages)
s.spanclass = spanclass
// 添加到 allspans
h.setSpans(s.base(), npages, s)
unlock(&h.lock)
})
// ...
return s
}
4.5 gcStart - GC 开始
源码位置 :src/runtime/mgc.go
go
// gcStart 开始一轮 GC
func gcStart(trigger gcTrigger) {
// ...
// --------------- 阶段 1: STW - 标记预备 ---------------
systemstack(func() {
stw = stopTheWorldWithSema(stwGCSweepTerm)
})
// 完成上一轮的清扫
systemstack(func() {
finishsweep_m()
})
// 清空 pool
clearpools()
// --------------- 阶段 2: 准备并发标记 ---------------
// 设置 gcphase
setGCPhase(_GCmark)
// 启用写屏障(会在 STW 中完成)
gcBgMarkPrepare()
// 标记当前的 tiny 块
gcMarkTinyAllocs()
// 启用辅助标记
atomic.Store(&gcBlackenEnabled, 1)
// --------------- 阶段 3: 开始世界,进入并发标记 ---------------
systemstack(func() {
now = startTheWorldWithSema(0, stw)
})
// ...
}
4.6 gcDrain - 标记对象
源码位置 :src/runtime/mgcmark.go
go
// gcDrain 扫描灰色对象并标记
func gcDrain(gcw *gcWork, flags gcDrainFlags) {
// ...
for {
// 获取工作
if work == 0 {
work = gcw.get()
if work == 0 {
// 没有更多工作
return
}
}
// 扫描对象
scanobject(work, gcw)
// ...
}
}
// scanobject 扫描一个对象,标记其引用
func scanobject(b uintptr, gcw *gcWork) {
// 获取对象类型信息
s := spanOfUnchecked(b)
size := s.elemsize
// 扫描所有指针槽位
for i := uintptr(0); i < size; i += goarch.PtrSize {
// 加载指针
p := *(*uintptr)(unsafe.Pointer(b + i))
// 检查是否是有效堆指针
if p != 0 && isInHeap(p) {
// 标记指针
shade(p)
}
}
}
4.7 shade - 标记对象
源码位置 :src/runtime/mgcmark.go
go
// shade 将对象标记为灰色(如果是白色)
func shade(p uintptr) {
// ...
// 获取对象的 span
s := spanOf(p)
if s == nil {
return
}
// 计算对象在 span 中的索引
objIndex := (p - s.base()) / s.elemsize
// 检查是否已经标记
if s.gcmarkBits.get(objIndex) {
return // 已经标记
}
// 标记对象
s.gcmarkBits.set(objIndex)
// 添加到工作队列
gcw.put(p)
}
4.8 gcMarkDone - 标记完成检查
源码位置 :src/runtime/mgc.go
go
// gcMarkDone 检查标记是否完成
func gcMarkDone() {
// ...
top:
// 检查是否所有工作都完成
if !(gcphase == _GCmark && gcIsMarkDone()) {
return
}
// 获取 world sema
semacquire(&worldsema)
// --------------- 阶段 1: 刷新本地工作队列 ---------------
gcMarkDoneFlushed = 0
forEachP(...) {
wbBufFlush1(pp)
pp.gcw.dispose()
if pp.gcw.flushedWork {
atomic.Xadd(&gcMarkDoneFlushed, 1)
}
}
// --------------- 阶段 2: 检查是否有新工作 ---------------
if gcMarkDoneFlushed != 0 {
// 有新工作,重新开始
semrelease(&worldsema)
goto top
}
// --------------- 阶段 3: STW - 标记终止 ---------------
systemstack(func() {
stw = stopTheWorldWithSema(stwGCMarkTerm)
})
// 禁用 mark worker
atomic.Store(&gcBlackenEnabled, 0)
// --------------- 阶段 4: 进入标记终止 ---------------
gcMarkTermination(stw)
}
4.9 gcMarkTermination - 标记终止
源码位置 :src/runtime/mgc.go
go
// gcMarkTermination 完成标记终止阶段
func gcMarkTermination(stw worldStop) {
// ...
// 设置为 mark termination 阶段
setGCPhase(_GCmarktermination)
// 完成最终标记工作
systemstack(func() {
gcMark(startTime)
})
// 设置回 GC off,准备清扫
setGCPhase(_GCoff)
// 开始清扫
systemstack(func() {
gcSweep(work.mode)
})
// 更新 pacing
systemstack(gcControllerCommit)
// 启动世界
systemstack(func() {
startTheWorldWithSema(now, stw)
})
// ...
}
4.10 mspan.sweep - 清扫 span
源码位置 :src/runtime/mgcsweep.go
go
// sweep 清扫 span,释放未标记的对象
func (s *mspan) sweep(preserve bool) bool {
// ...
// --------------- 阶段 1: 准备 ---------------
// 交换 allocBits 和 gcmarkBits
oldBits := s.allocBits
s.allocBits = s.gcmarkBits
s.gcmarkBits = newMarkBits(s.nelems)
// --------------- 阶段 2: 扫描并计算空闲对象 ---------------
// 扫描位图,收集空闲对象
// ...
// --------------- 阶段 3: 更新 span 状态 ---------------
// 更新 sweepgen
s.sweepgen = mheap_.sweepgen
// --------------- 阶段 4: 处理完全空闲的 span ---------------
if s.allocCount == 0 {
// 完全空闲,归还给 heap
mheap_.freeSpan(s, preserve)
return true
}
// --------------- 阶段 5: 还有对象,返回到 mcentral ---------------
return false
}
5. 基于当前项目的内存与 GC 专项复盘
5.1 当前项目源码分析
由于我们现在就在 Go 官方源码仓库(D:\dev\code\github\go),我们将分析 Go 编译器和 runtime 本身的内存行为。
5.1.1 项目结构概览
go/
├── src/
│ ├── runtime/ # 我们刚分析的核心
│ ├── cmd/
│ │ ├── compile/ # Go 编译器
│ │ ├── link/ # 链接器
│ │ └── go/ # go 命令
│ └── ...
└── ...
5.2 典型逃逸案例分析(基于 Go 源码)
案例1:接口调用导致的逃逸
源码位置 :src/cmd/compile/internal/escape/escape.go
go
// 在编译器中,很多地方使用 interface{} 导致逃逸
func walk(n *Node, init *Nodes) *Node {
// ...
switch n.Op {
case OAS2IFACE:
// 接口转换,右侧通常会逃逸
// ...
}
// ...
}
分析:
- 当值被赋给 interface{} 类型时,值会逃逸
- 这是因为 interface{} 需要在堆上存储动态类型信息
案例2:闭包捕获变量
源码位置 :src/runtime/proc.go
go
// newproc 中使用闭包
func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerpc uintptr) {
// ...
systemstack(func() {
// 闭包捕获了多个变量,这些变量逃逸
newg := newg
fn := fn
narg := narg
// ...
})
// ...
}
分析:
- 闭包捕获的变量如果需要在闭包外访问,会逃逸
newg、fn等都会逃逸到堆
案例3:发送到通道
源码位置 :src/runtime/chan.go
go
func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
// ...
// ep 指向的数据通常会逃逸
// ...
}
分析:
- 发送到通道的值会逃逸
- 因为通道中的数据需要在不同 goroutine 间传递
5.3 堆对象热点分析
热点1:编译器的 AST 节点分配
Go 编译器在编译过程中会分配大量的 AST 节点:
go
// src/cmd/compile/internal/syntax/nodes.go
type Node interface {
// ...
}
type ExprNode struct {
// ...
}
特点:
- 短期对象,编译后立即释放
- 数量巨大(数百万级)
- 对 GC 造成压力
热点2:runtime 的 span 分配
go
// src/runtime/mheap.go
// span 分配频繁
特点:
- 中等生命周期
- 大小固定
- 可以重用
5.4 内存隐患与可优化点
隐患1:编译器内存峰值
Go 编译器在编译大型项目时会有内存峰值:
编译阶段内存使用:
- 语法分析:~10%
- 类型检查:~30%
- SSA 生成:~70%
- 代码生成:~90% (峰值)
- 链接:~50%
优化方案:
- 更积极的内存复用
- 分阶段 GC
- 使用临时 arena(Go 1.20+)
隐患2:runtime 元数据内存开销
heapArena 有一些元数据开销:
go
type heapArena struct {
spans [pagesPerArena]*mspan // 8KB (64MB arena)
pageInUse [pagesPerArena/8]uint8 // 1KB
// ...
}
分析:
- 元数据开销约 0.015%
- 对于大堆,这是可接受的
5.5 实战优化建议
优化1:使用 sync.Pool 重用对象
go
// 类似 Go 编译器的做法
var nodePool = sync.Pool{
New: func() interface{} {
return new(ExprNode)
},
}
func newExprNode() *ExprNode {
return nodePool.Get().(*ExprNode)
}
func freeExprNode(n *ExprNode) {
// 清理
*n = ExprNode{}
nodePool.Put(n)
}
优化2:使用对象 arena
Go 1.20+ 引入了 arena 包:
go
import "arena"
func compileStage() {
a := arena.NewArena()
defer a.Free()
// 从 arena 分配 AST 节点
node := arena.New[ExprNode](a)
// ...
}
优化3:调整 GOGC
对于编译场景,可以调整 GOGC:
bash
# 增加 GC 触发阈值,减少 GC 频率
GOGC=200 go build large_project.go
# 或者使用软内存限制
GOMEMLIMIT=4GiB go build large_project.go
6. 大厂面试高频真题 + 源码级标准答案
6.1 内存分配面试题
题目1:Go 的内存分配器是如何工作的?
考察点:多级缓存架构、大小类、span 机制
源码级答案:
Go 使用类似 TCMalloc 的多级分配器:
-
mcache(P 本地):
- 每个 P 有自己的 mcache
- 无锁分配,速度极快
- 按 spanClass 缓存 span
- 源码位置:
src/runtime/mcache.go
-
mcentral(全局):
- 每个 size class 一个 mcentral
- 管理 span 的中央池
- 源码位置:
src/runtime/mcentral.go
-
mheap(全局):
- 管理从 OS 获取的内存
- 以 heapArena(64MB)为单位管理
- 源码位置:
src/runtime/mheap.go
分配流程:
- 小对象(<32KB):从 mcache 的对应 size class 分配
- 大对象(>32KB):直接从 mheap 分配
- 微对象(<16B, noscan):使用 tiny allocator 打包分配
面试官追问:为什么要设计这么多级?
回答:
- 减少锁竞争:mcache 无锁,mcentral 很少竞争
- 减少碎片:size class 设计
- 提高分配速度:mcache 快速路径
题目2:什么是逃逸分析?如何判断对象是否逃逸?
考察点:逃逸分析原理、常见逃逸场景
源码级答案:
逃逸分析定义:
- 编译器在编译阶段分析变量的生命周期
- 确定变量应该分配在栈还是堆
- 源码位置:
src/cmd/compile/internal/escape/escape.go
常见逃逸场景:
-
返回局部变量指针:
gofunc f() *int { x := 42 return &x // x 逃逸 } -
被闭包捕获:
gofunc f() func() { x := 42 return func() { println(x) } // x 逃逸 } -
发送到通道:
gofunc f(ch chan *int) { x := 42 ch <- &x // x 逃逸 } -
存储到堆上的结构:
gotype T struct { p *int } func f(t *T) { x := 42 t.p = &x // x 逃逸 } -
过大的对象:
- 超过栈大小限制(默认栈初始 2KB,但会增长)
如何查看逃逸分析结果:
bash
go build -gcflags="-m" main.go
题目3:span 是什么?spanClass 如何构成?
考察点:span 结构、size class、noscan 标志
源码级答案:
span 定义:
- span 是内存管理的基本单位
- 由连续的多个页(8KB)组成
- 源码位置:
src/runtime/mheap.go
span 结构:
go
type mspan struct {
startAddr uintptr // 起始地址
npages uintptr // 页数
freeindex uintptr // 下一个空闲索引
nelems uintptr // 对象总数
allocCache uint64 // 分配缓存
allocBits *gcBits // 分配位图
gcmarkBits *gcBits // GC 标记位图
sweepgen uint32 // 清扫世代
// ...
}
spanClass 构成:
go
// spanClass 编码了 size class 和 noscan 标志
type spanClass uint8
func makeSpanClass(sizeclass uint8, noscan bool) spanClass {
if noscan {
return spanClass(sizeclass<<1) | 1
}
return spanClass(sizeclass << 1)
}
func (sc spanClass) sizeclass() uint8 {
return uint8(sc >> 1)
}
func (sc spanClass) noscan() bool {
return sc&1 != 0
}
size class 数量:68 个(0-67)
- 最大的小对象:32KB
- 超过 32KB 的是大对象
6.2 GC 面试题
题目4:Go 的 GC 是如何工作的?三色标记是什么?
考察点:GC 完整流程、三色标记原理
源码级答案:
Go GC 阶段:
-
标记预备(STW):
- 启用写屏障
- 完成上一轮清扫
- 源码位置:
gcStart()insrc/runtime/mgc.go
-
并发标记:
- 与用户代码并行运行
- 使用三色标记
- 写屏障保护
- 源码位置:
gcDrain()insrc/runtime/mgcmark.go
-
标记终止(STW):
- 完成最终标记
- 禁用写屏障
- 源码位置:
gcMarkTermination()
-
并发清扫:
- 与用户代码并行
- 回收白色对象
- 源码位置:
mspan.sweep()
三色标记:
- 白色:未标记,最终回收
- 灰色:已标记,待扫描
- 黑色:已标记,已扫描
三色不变性:
- 黑色对象不能引用白色对象(强)
- 或者黑色可以引用白色,但需要灰色保护(弱)
- Go 使用弱三色不变性 + 写屏障
题目5:写屏障是什么?Go 为什么需要写屏障?
考察点:写屏障原理、漏标问题
源码级答案:
写屏障定义:
- 在指针写入时执行的一段辅助代码
- 用于保持三色不变性
- 源码位置:
src/runtime/mbarrier.go
为什么需要写屏障:
漏标问题:
- 黑色对象新增对白色对象的引用
- 灰色对象删除对白色对象的引用
- 结果:白色对象可能漏标被错误回收
Go 的混合写屏障:
go
// 写屏障伪代码
writePointer(slot, ptr) {
shade(*slot) // 标记旧值
shade(ptr) // 标记新值
*slot = ptr
}
源码实现:
- 汇编实现:
src/runtime/asm_amd64.s中的gcWriteBarrier* - Go 包装:
src/runtime/mbarrier.go
写屏障开启时机:
- 仅在并发标记阶段(
gcphase == _GCmark) - 标记预备阶段启用
- 标记终止阶段禁用
题目6:STW 是什么时候发生的?持续多久?如何优化?
考察点:STW 时机、STW 时间、优化策略
源码级答案:
STW 触发点:
-
标记预备(sweep termination):
- 进入 GC 时
- 典型时间:10-50 µs
- 源码:
stopTheWorldWithSema(stwGCSweepTerm)
-
标记终止(mark termination):
- GC 结束时
- 典型时间:100-500 µs
- 源码:
stopTheWorldWithSema(stwGCMarkTerm)
STW 做什么:
go
func stopTheWorldWithSema(reason stwReason) worldStop {
// 1. 抢占所有 P
// 2. 等待所有 G 到达安全点
// 3. 停止后台任务
// ...
}
如何优化 STW 时间:
-
减少 STW 阶段工作量:
- 把工作移到并发阶段
- 如:并发清扫
-
安全点优化:
- 在函数序言和循环回边插入安全点
- 避免长时间无安全点
-
异步停止:
- 不需要等待所有 G 同时停止
- 逐个停止
-
调优参数:
- GOGC:调整 GC 频率
- GOMEMLIMIT:软内存限制
题目7:GOGC 是如何工作的?如何调优?
考察点:GC pacer、触发机制、参数调优
源码级答案:
GOGC 定义:
- GC 触发的堆增长比例
- 默认值:100(即堆增长 100% 时触发 GC)
- 源码位置:
src/runtime/mgcpacer.go
GC 触发公式:
heapGoal = heapMarked + (heapMarked * GOGC / 100)
例如:
- GOGC=100,上次标记后堆大小 100MB
- 下一次触发 GC 时:100 + 100*100% = 200MB
调优建议:
-
内存充足,降低 GC 频率:
bashGOGC=200 ./app # 堆增长 200% 才触发 -
内存紧张,更频繁 GC:
bashGOGC=50 ./app # 堆增长 50% 就触发 -
使用软内存限制(Go 1.19+):
bashGOMEMLIMIT=4GiB ./app # 目标内存使用 4GB
查看 GC 统计:
go
import "runtime/debug"
debug.SetGCPercent(200)
debug.ReadGCStats()
题目8:如何观察和分析 Go 的内存和 GC 行为?
考察点:工具使用、实战排查
源码级答案:
1. GODEBUG 环境变量:
bash
# 打印 GC trace
GODEBUG=gctrace=1 ./app
# 输出示例:
gc 1 @0.021s 0%: 0.018+0.23+0.004 ms clock, 0.14+0/0.058/0.040+0.032 ms cpu, 4->4->0 MB, 5 MB goal, 4 P
# 解释:
# gc 1: 第 1 次 GC
# @0.021s: 程序启动后 0.021s
# 0%: GC CPU 占用率
# 0.018+0.23+0.004: STW(mark) + concurrent + STW(mark term)
# 4->4->0: heap_live -> heap_live after mark -> heap_live after sweep
# 5 MB goal: heap goal
# 4 P: GOMAXPROCS
2. pprof 分析:
go
import _ "net/http/pprof"
import "net/http"
func main() {
go func() {
http.ListenAndServe(":6060", nil)
}()
// ...
}
bash
# 查看堆分配
go tool pprof http://localhost:6060/debug/pprof/heap
# 查看内存分配(allocs)
go tool pprof http://localhost:6060/debug/pprof/allocs
# 查看 GC 追踪
curl http://localhost:6060/debug/pprof/trace?seconds=10 > trace.out
go tool trace trace.out
3. runtime.ReadMemStats:
go
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Printf("HeapAlloc: %v MB\n", stats.HeapAlloc/1024/1024)
fmt.Printf("HeapSys: %v MB\n", stats.HeapSys/1024/1024)
fmt.Printf("NumGC: %v\n", stats.NumGC)
4. trace 工具:
bash
# 生成 trace
go test -trace trace.out
# 查看 trace
go tool trace trace.out
6.3 实战场景面试题
题目9:内存泄漏如何排查?Go 有哪些常见内存泄漏?
考察点:内存泄漏模式、排查方法
源码级答案:
常见内存泄漏:
-
Goroutine 泄漏:
gofunc leak() { ch := make(chan int) go func() { <-ch // 永远阻塞 }() // goroutine 泄漏! } -
时间泄漏:
gotime.AfterFunc(1*time.Hour, func() { // 定时器在 1 小时内不会释放 }) -
未关闭的资源:
gofunc f() { resp, _ := http.Get("https://example.com") // 忘记 resp.Body.Close() } -
sync.Pool 误用:
- Pool 可能保留对象引用
- 特别是有 finalizer 的对象
排查方法:
bash
# 1. 使用 pprof heap,对比两个时间点
go tool pprof http://localhost:6060/debug/pprof/heap
# 等待一段时间
go tool pprof http://localhost:6060/debug/pprof/heap
# 在 pprof 中使用 diff_base
# 2. 使用 goroutine profile
go tool pprof http://localhost:6060/debug/pprof/goroutine
# 查看是否有异常多的 goroutine
题目10:什么是内存碎片?Go 如何处理内存碎片?
考察点:碎片类型、Go 的解决方案
源码级答案:
内存碎片类型:
-
内部碎片:
- 分配的内存比实际需要的大
- 成因:size class 舍入
- Go 的处理:优化 size class 设计
-
外部碎片:
- 有足够内存但没有连续的页
- 成因:span 离散释放
- Go 的处理:pageAlloc 的地址序首次适配
Go 的解决方案:
-
Size Classes:
- 预定义 68 个大小类
- 减少内部碎片
-
Span 合并:
- 相邻的空闲 span 可以合并
- 源码:
mheap.coalesce()
-
延迟归还:
- 不是立即归还内存给 OS
- 保留一些内存作为缓存
-
Scavenger:
- 后台归还未使用的内存
- 源码:
bgscavenge()
7. 工程化优化总结与线上排查思路
7.1 编码优化建议
优化1:减少对象逃逸
反模式:
go
// 不必要的指针返回
func NewUser() *User {
return &User{Name: "foo"} // 逃逸
}
// 更好的写法
func NewUser() User {
return User{Name: "foo"} // 不逃逸
}
验证逃逸分析:
bash
go build -gcflags="-m -m"
优化2:使用对象池
go
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 4096)
},
}
func process() {
buf := bufferPool.Get().([]byte)
defer bufferPool.Put(buf[:0]) // 重置并归还
// 使用 buf
// ...
}
注意:
- 对象应该是同质化的
- 归还时要清理状态
- 不是所有场景都适合 Pool
优化3:预分配容量
go
// 反模式
func bad() []string {
var s []string
for i := 0; i < 1000; i++ {
s = append(s, strconv.Itoa(i)) // 多次扩容
}
return s
}
// 好的写法
func good() []string {
s := make([]string, 0, 1000) // 预分配
for i := 0; i < 1000; i++ {
s = append(s, strconv.Itoa(i))
}
return s
}
优化4:避免频繁的小对象分配
go
// 反模式
func processItems(items []Item) {
for _, item := range items {
w := &Worker{item: item} // 每次循环分配
w.process()
}
}
// 好的写法
func processItems(items []Item) {
w := &Worker{} // 重用
for _, item := range items {
w.item = item
w.process()
}
}
7.2 GC 参数调优
调优1:GOGC 调整
| 场景 | GOGC 值 | 理由 |
|---|---|---|
| 内存充足,追求低延迟 | 200-500 | 减少 GC 频率 |
| 内存紧张,追求低内存 | 20-50 | 更频繁回收 |
| 批处理任务,吞吐量优先 | 500+ | 减少 GC 次数 |
| 默认场景 | 100 | 平衡 |
调优2:GOMEMLIMIT 使用(Go 1.19+)
bash
# 设置软内存限制为 4GB
GOMEMLIMIT=4GiB ./app
优点:
- 比 GOGC 更直观
- 自动调整 GC 频率
- 防止 OOM
调优3:GOMAXPROCS 设置
go
runtime.GOMAXPROCS(runtime.NumCPU())
GC 与 GOMAXPROCS:
- GC 使用约 25% 的 CPU
- 更多 P 意味着更多并行标记能力
7.3 线上问题排查链路
排查步骤1:初步观察
bash
# 1. 查看进程状态
top -p <pid>
# 2. 查看 GC 统计
GODEBUG=gctrace=1 ./app # 或者重启时开启
排查步骤2:pprof 采样
go
// 在程序中开启
import _ "net/http/pprof"
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
bash
# 1. 堆内存采样
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/heap
# 2. 分配采样
go tool pprof http://localhost:6060/debug/pprof/allocs
# 3. goroutine 采样
go tool pprof http://localhost:6060/debug/pprof/goroutine
# 4. trace 采样(10秒)
curl -o trace.out http://localhost:6060/debug/pprof/trace?seconds=10
go tool trace trace.out
排查步骤3:深入分析
分析内存泄漏:
bash
# 对比两个时间点的 heap profile
go tool pprof -base heap.1.pprof heap.2.pprof
top # 看增长最多的
分析 GC 停顿:
bash
# 使用 trace 工具查看 GC 阶段
go tool trace trace.out
# 查看 GC timeline
7.4 pprof 核心视图解读
heap profile 视图
Showing nodes accounting for 10MB, 100% of 10MB total
Dropped 10 nodes (cum <= 0.05MB)
flat flat% sum% cum cum%
5MB 50.0% 50.0% 5MB 50.0% main.newObject
3MB 30.0% 80.0% 3MB 30.0% main.process
2MB 20.0% 100% 2MB 20.0% main.other
flat :函数自身分配的内存
cum:函数及其调用者分配的总内存
trace 视图
GC Timeline:
├─ GC Cycle 1
│ ├─ Mark Phase (concurrent)
│ ├─ Mark Termination (STW)
│ └─ Sweep Phase (concurrent)
└─ GC Cycle 2
关注:
- STW 时间
- GC 频率
- 目标堆大小与实际堆大小
7.5 常见问题与解决方案速查
| 问题 | 现象 | 排查工具 | 解决方案 |
|---|---|---|---|
| 内存泄漏 | 堆持续增长 | pprof heap, goroutine | 修复泄漏源 |
| GC 频繁 | 高 CPU,小堆 | gctrace | 调大 GOGC/GOMEMLIMIT |
| GC 停顿长 | 延迟峰值 | trace | 减少堆大小,优化分配 |
| 分配慢 | 延迟高 | pprof allocs | 对象池、预分配 |
| Goroutine 泄漏 | Goroutine 数增长 | pprof goroutine | 修复阻塞点 |