低延迟服务推荐 gogc=50 起步,若 stw 超 0.8ms 再降至 30 并配 gomemlimit;禁用 runtime.gc();高吞吐批处理可用 gogc=200~500 但需严控内存;gogc=off 禁止用于生产。
低延迟服务该设 GOGC=30 还是 50?
对实时交易、游戏后端、API 网关这类服务,单次 GC 停顿超过 1ms 就可能丢请求或卡帧。GOGC 不是越小越好——设成 GOGC=20 会让 GC 频率翻倍,CPU 开销陡增,反而拖慢整体吞吐。
推荐从 GOGC=50 起步:堆增长 50% 就触发回收,能压住峰值内存又不至于让 GC 太“喘不过气”。若实测 GODEBUG=gctrace=1 输出中仍有 >0.8ms 的 STW,再降到 GOGC=30,并务必搭配 GOMEMLIMIT=450MiB(假设容器 limit 是 512MiB),防止 GC 来不及介入就被 OOMKilled。
- 禁用
runtime.GC()手动触发——它会强制 STW,破坏低延迟稳定性 - 必须开
GODEBUG=gctrace=1观察实际 pause time,别只看配置改了没 - 如果停顿仍高,大概率是对象逃逸严重,用
go tool pprof -alloc_space查分配热点,而不是继续调低 GOGC
高吞吐批处理能不能设 GOGC=500?
可以,但得盯紧内存。日志聚合、ETL、离线计算这类任务不care单次延迟,更怕 GC 抢 CPU。设 GOGC=200~500 能显著降低 GC 次数,但代价是堆可能膨胀到上次 GC 后存活量的 3~5 倍。
比如上次 GC 后存活 200MB,GOGC=500 意味着要等堆涨到 1200MB 才触发下一次——这在裸机上没问题,在 K8s 里可能直接被 kill。
- 必须监控
MemStats.Alloc和MemStats.Sys,发现Alloc持续单向上涨就说明有泄漏,不是 GC 能解决的 - 避免在循环里
make([]byte, 1 这种大对象分配,哪怕 GOGC 再高,也会触发辅助 GC 导致抖动 - 优先用
sync.Pool复用缓冲区,比调高 GOGC 更治本
GOGC=off 或 SetGCPercent(0) 能不能用?
不能用于生产环境,哪怕只是“临时试试”。GOGC=off 或 debug.SetGCPercent(0) 会完全禁用 GC,堆内存只增不减,直到 OOM 或进程崩溃。