直接回答:GOGC 控制 GC 触发时机:堆增长到上次 GC 后存活堆的 (1+GOGC/100) 倍时触发,默认 100 即翻倍即收——调大省 CPU 费内存,调小反之,off 则只靠 GOMEMLIMIT。GOMEMLIMIT(1.19+)是内存软上限:逼近时 GC 更频繁,宁可耗 CPU 也不越线。容器标配:GOMEMLIMIT 设为限额的 80%~90%,GOGC 视 CPU 预算微调。
展开解析:容器坑的成因:Go runtime 默认按宿主机核数与内存做决策(1.25 起 GOMAXPROCS 感知 cgroup),K8s 里 limit 512Mi 的容器看到 64Gi 宿主内存,堆随便涨到 1Gi 触发 cgroup OOM——进程直接被 SIGKILL,没有 panic 日志。解法两条:GOMEMLIMIT=400MiB(留余量给非堆内存:goroutine 栈、内核缓冲、cgo 分配都不受 GOMEMLIMIT 管);GOMAXPROCS 配 automaxprocs 库或升级 1.25,否则 CPU 限 2 核却按 64 核起 P,调度自旋吃掉配额。调优方法论:先定量——runtime.MemStats 的 HeapLive(GC 后真实存活)、GC CPU 占比(trace 统计),HeapLive 小而 GC 频繁说明垃圾产生快,GOGC 调大或减分配;HeapLive 本身大接近限额,调 GOGC 无用,要么减内存要么提限额。常见误操作:GOGC=off 不设 limit 直接裸奔;把 GOMEMLIMIT 顶格设成限额(非堆内存无处可去照样 OOM);试图用 GOGC 治内存泄漏——泄漏是 bug,GC 参数只调行为不治病。辅助手段:debug.SetGCPercent 可运行期改,做动态降级开关。
追问方向:ballast(压舱石)大法为什么被 GOMEMLIMIT 取代?GC 辅助标记(assist)何时拖慢请求?
(约 490 字)