为k8s pod 增加golang 程序gc trace:
env:
- name: GODEBUG
value: "gctrace=1,scavtrace=1"
Go GC Trace 输出格式详解
以这条为例:
gc 14 @165.909s 0%: 0.045+0.79+0.028 ms clock, 0.36+0.32/1.4/2.3+0.22 ms cpu, 4063->4191->2147 MB, 4355 MB goal, 0 MB stacks, 0 MB globals, 8 P
第一段:基本信息
gc 14 @165.909s 0%
| 字段 | 示例值 | 含义 |
|---|
gc 14 | 14 | 这是程序启动以来的第 14 次 GC |
@165.909s | 165.909 | 程序启动后 165.909 秒触发 |
0% | 0 | 从程序启动到现在,GC 累计占用的 CPU 时间百分比 |
第二段:Wall Clock 时间(实际经过时间)
0.045+0.79+0.028 ms clock
GC 分为三个阶段,对应三个数值:
| 阶段 | 示例值 | 说明 |
|---|
| STW Sweep Termination | 0.045 ms | 第一次 Stop-The-World:暂停所有 goroutine,结束上一轮的清扫工作,准备开始标记 |
| Concurrent Mark & Scan | 0.79 ms | 并发阶段:标记所有可达对象。此阶段与应用 goroutine 同时运行,不暂停程序 |
| STW Mark Termination | 0.028 ms | 第二次 Stop-The-World:暂停所有 goroutine,完成标记,启动清扫 |
💡 真正影响延迟的是第 1 和第 3 个值(STW 暂停) ,你的数据中均 < 0.2ms,非常优秀。
第三段:CPU 时间(所有核心累计)
0.36+0.32/1.4/2.3+0.22 ms cpu
| 字段 | 示例值 | 含义 |
|---|
| STW Sweep Termination CPU | 0.36 ms | 第一次 STW 在所有 P 上消耗的 CPU 总时间 |
| Assist(辅助标记) | 0.32 ms | 分配内存的 goroutine 被迫帮忙做标记的 CPU 时间 |
| Dedicated(专用 GC 线程) | 1.4 ms | 专门用于 GC 标记的后台 goroutine 的 CPU 时间 |
| Idle(空闲窃取) | 2.3 ms | 空闲 P 偷过来做 GC 标记的 CPU 时间 |
| STW Mark Termination CPU | 0.22 ms | 第二次 STW 在所有 P 上消耗的 CPU 总时间 |
格式:STW1 + assist/dedicated/idle + STW2
💡 Assist 高意味着分配压力大——分配速度太快,GC 来不及标记,迫使分配者"交税"帮忙做标记。你的 assist 值很低(0.32ms),说明没有压力。
第四段:堆内存变化(最重要 ⭐)
4063->4191->2147 MB
| 字段 | 示例值 | 含义 |
|---|
| GC 开始时堆大小 | 4063 MB | 触发 GC 时的堆使用量(包含可达 + 不可达对象) |
| GC 结束时堆大小 | 4191 MB | GC 标记阶段结束时堆大小(因为并发标记期间,应用仍在分配新对象,所以可能比开始时更大) |
| 存活对象大小 | 2147 MB | 标记完成后,仍然可达的对象总大小。这是最关键的指标 |
回收量 = GC 结束时堆大小 - 存活对象 = 4191 - 2147 = 2044 MB
第五段:GC 目标
4355 MB goal
| 字段 | 示例值 | 含义 |
|---|
| Goal | 4355 MB | 下次触发 GC 的堆大小阈值。当堆增长到这个值时触发下次 GC |
Goal 的计算公式(默认 GOGC=100):
goal ≈ 存活对象 × (1 + GOGC/100)
= 2147 × 2
= ~4294 MB(实际会有 runtime 的微调)
第六段:栈和全局变量
0 MB stacks, 0 MB globals
| 字段 | 示例值 | 含义 |
|---|
| Stacks | 0 MB | 所有 goroutine 栈使用的内存(向上取整到 MB,小于 1MB 显示为 0) |
| Globals | 0 MB | 全局变量(包含 BSS 段等)扫描的内存量 |
Go 1.22+ 开始输出这两个字段,帮助判断非堆内存的占用。
第七段:处理器数量
8 P
| 字段 | 示例值 | 含义 |
|---|
| P | 8 | Go scheduler 使用的逻辑处理器数量(等于 GOMAXPROCS,默认等于 CPU 核心数) |
完整格式模板
gc {次数} @{时间}s {CPU占比}%: {STW1}+{并发标记}+{STW2} ms clock, {STW1_cpu}+{assist}/{dedicated}/{idle}+{STW2_cpu} ms cpu, {GC前堆}->{GC后堆}->{存活} MB, {goal} MB goal, {stacks} MB stacks, {globals} MB globals, {P} P
快速看问题的优先级
| 优先级 | 看什么 | 健康标准 |
|---|
| ⭐⭐⭐ | 存活对象是否持续增长 | 稳定 = 无泄漏,持续增长 = 可能泄漏 |
| ⭐⭐ | STW 暂停时间(第1和第3个值) | < 1ms 优秀,> 10ms 需关注 |
| ⭐ | GC CPU 占比 | < 5% 正常,> 25% 需优化 |
| ⭐ | Assist 时间 | 接近 0 最好,过高说明分配压力大 |