← ClaudeAtlas

go-runtimelisted

Go 运行时原理专家(Go 1.25.9+ 基线)- 深入 GMP 调度器(work-stealing、抢占、netpoll)、GC(三色标记+混合写屏障+pacer)、内存分配器(mspan/mcache/mcentral/mheap)、Swiss Tables map 实现(1.24+)、Channel(hchan)、defer 演进(open-coded)、接口 itab、反射成本、sync 原语底层。适用:性能问题根因分析、异常行为排查(GC 抖动、调度延迟、死锁)、运行时调优决策依据、面试/架构评审中的原理解释、GODEBUG 调试解读。不适用:性能优化实操(用 go-performance)、业务代码编写(用 golang-patterns)、简单 bug 修复(无需原理)。触发词:runtime, 运行时, GMP, scheduler, 调度器, goroutine 调度, GC, garbage collector, 垃圾回收, 三色标记, 写屏障, pacer, mcache, mcentral, mheap, mspan, Swiss Tables, hchan, channel 底层, defer 实现, itab, netpoll, GODEBUG, gctrace, schedtrace
omeyang/Thoth · ★ 0 · AI & Automation · score 73
Install: claude install-skill omeyang/Thoth
# Go 运行时原理专家 回答运行时原理问题或提供调试依据:$ARGUMENTS **基线 Go 1.25.9+。所有内部机制以当前版本为准;历史演进作对比说明。** --- ## 为什么学运行时 **不是为了背书**,是为了: 1. 看懂 `GODEBUG=gctrace=1` / `schedtrace=1000` / `allocfreetrace=1` 输出 2. 判断"该不该优化"的根本依据(`sync.RWMutex` vs `Mutex`、`sync.Map` vs 分片锁) 3. 诊断异常行为:STW 抖动、goroutine 泄漏、调度延迟、OOM 4. 评估新版本影响(如 1.24 Swiss Tables 对 map 性能分布的改变) 想做具体优化 → `go-performance` 技能;这里讲**为什么**。 --- ## §1 GMP 调度器 ### 1.1 三角色 | 角色 | 含义 | 典型数量 | |---|---|---| | **G** (Goroutine) | 用户协程,栈 + PC + 状态 | 可达百万 | | **M** (Machine) | OS 线程 | 少量,由 `GOMAXPROCS` + syscall 阻塞动态决定 | | **P** (Processor) | 调度上下文,持有本地 runqueue | `GOMAXPROCS` 个 | **关系**: - M 必须绑 P 才能运行 G - P 数量通常 = CPU 核心数(`GOMAXPROCS`) - Go 1.25 起:Linux 下自动识别 cgroup CPU quota ### 1.2 调度循环 ``` M 有 P,开始调度: 1. 从 P 的本地 runqueue 取 G(快速路径) 2. 如果本地空: a. 从全局 runqueue 取(每 61 次也主动检查,避免饥饿) b. 从其他 P 偷一半(work-stealing) c. 检查 netpoll 3. 执行 G,直到阻塞或时间片到 4. 归还 P 给 M 池或主动让出 ``` ### 1.3 抢占 - **协作式**(Go 1.13 前):函数调用插入检查点,死循环无调用无法抢占 - **信号抢占**(Go 1.14+):`SIGURG` 强制中断,即使死循环也能抢 - **时间片**:10 ms,到期主动让出(异步抢占实现) - `GODEBUG=asyncpreemptoff=1` 关闭信号抢占(调试用;生产勿开) ### 1.4 系统调用阻塞 ``` G 执行 syscall(阻塞性): 1. M 脱离 P(sysmon 监测到阻塞 > 20μs) 2. P 被其他 M 接管继续调度其他 G 3. syscall 返回后 M 尝试拿 P: a. 有空闲 P → 继续 b. 无 → G 放入全局 runqueue,M 睡眠 ``` ### 1.5 netpoll 非阻塞 I/O(net/http、database/sql 底层)用 netpoll: - Linux: epoll - macOS/BSD: kqueue - Windows: IOCP **关键**:G 在 netpoll 等待时**不占 P、不占 M**。这是 Go 能起百万 goroutine 的根本。 ### 1.6 GODEBUG schedtrace ```ba