应优先排查 goroutine 泄漏和 gc 频次:通过 /debug/pprof/goroutines 观察突增趋势,确保 http 超时、channel 接收、context cancel 正确;用 strings.builder、sync.pool(仅限可 reset 对象)和逃逸分析优化内存分配。
减少 goroutine 泄漏导致的调度开销
goroutine 泄漏是 Go 服务响应变慢的隐性元凶——泄漏的 goroutine 不仅占用内存,还会持续被调度器扫描,拖慢整个 runtime 的调度效率。常见于未关闭的 channel 接收、超时未处理的 HTTP 客户端请求、或忘记 cancel() 的 context.Context。
- HTTP 客户端务必设置
Timeout或用context.WithTimeout()控制生命周期 - 对带缓冲 channel 的接收操作,避免无条件
for range;改用select+default或显式退出条件 - 启动 goroutine 前,优先考虑是否能复用(如用
sync.Pool缓存结构体)而非新建 - 用
pprof/goroutines持续观察 goroutine 数量趋势,突增即排查泄漏点
避免频繁小对象分配触发 GC 压力
Go 的 GC 虽为并发三色标记,但高频小对象(如循环中创建 map[string]string、struct{} 或字符串拼接)仍会快速填满 young generation,导致 STW 时间上升、响应毛刺明显。
- 用
strings.Builder替代+拼接字符串,尤其在日志、响应体构造场景 - 将短生命周期结构体字段提前声明为指针或切片元素,避免每次循环
make([]T, 0, N)分配新底层数组 - HTTP handler 中避免在请求路径上
json.Unmarshal到新 struct;可复用sync.Pool管理解析目标对象 - 用
go tool compile -gcflags="-m -m"检查变量是否逃逸到堆,针对性优化
合理使用 sync.Pool 减少重复初始化开销
sync.Pool 对高频创建/销毁的对象(如 JSON 解码器、bytes.Buffer、自定义 parser)效果显著,但滥用反而引入锁竞争或缓存污染——它不保证对象复用,也不强制清理。