Goroutine泄漏因无法正常退出导致内存增长,需用Context传递取消信号、通过select监听ctx.Done()实现优雅退出,结合WaitGroup确保任务完成,并利用pprof分析阻塞协程定位问题。
Go 语言中,Goroutine 泄漏是导致内存持续增长和系统性能下降的常见问题。它发生在 Goroutine 启动后因逻辑错误而无法正常退出,比如永久阻塞在未关闭的 channel 上或陷入没有退出条件的循环。避免和修复这类问题,关键在于主动管理生命周期和利用工具进行检测。
对于有取消需求的 Goroutine,context 是最标准、最推荐的解决方案。它允许你从一个中心点向下传递取消信号,确保所有关联的 Goroutine 都能优雅退出。
核心做法是让 Goroutine 在一个 select 语句中监听其 ctx.Done() 通道。当父级调用 cancel() 函数时,Done() 通道会关闭,被阻塞的 Goroutine 就能收到信号并返回。
当你需要确保一组 Goroutine 全部执行完毕后再继续(例如在 main 函数结束前),应使用 sync.WaitGroup。这可以防止主程序过早退出,从而“泄露”那些还在运行的子任务。
泄漏当怀疑有 Goroutine 泄漏时,pprof 是最有效的诊断工具。通过它可以查看当前所有 Goroutine 的调用堆栈,找出那些处于 “chan receive”、“IO wait” 等阻塞状态且数量异常增多的协程。
启用方法很简单:在程序中导入 _ "net/http/pprof" 包并启动一个 HTTP 服务。然后访问 /debug/pprof/goroutine?debug=2 端点,就能获得一份详细的报告,精确指出是哪一行代码启动了泄漏的 Goroutine。
基本上就这些。养成“不启动无法停止的 Goroutine”的习惯,结合 context 和 WaitGroup 进行管理,并善用 pprof 这类工具,就能有效规避绝大多数的 Goroutine 泄漏问题。