错误。go 语言中 goroutine 在其启动的函数返回后自动结束;main 函数返回则整个程序立即终止,所有非主 goroutine 被强制中止,不会继续运行。

Go 语言中 goroutine 不会因为函数返回就自动消失,只要它还在运行(哪怕卡在 c 或 <code> 上),就不会被回收——这是绝大多数 goroutine 泄漏的根源。
goroutine 卡在无缓冲 channel 发送上就永远不退出
无缓冲 channel 的发送操作是同步阻塞的:必须等对面有 goroutine 执行接收,c 才能返回。如果只接收一次,但启动了多个发送者,剩下的就会永久阻塞。
- 阻塞的 goroutine 被视为“活跃”,其栈、闭包变量、对 channel 的引用全部无法被 GC 清理
- channel 本身也因被阻塞 goroutine 持有而无法回收(即使作用域已结束)
- 现象:pprof 查看
runtime.goroutines持续增长,go tool trace显示大量 goroutine 停在chan send状态
用带缓冲 channel 替代无缓冲 channel 是最简修复方式
缓冲区只要能容纳至少一个值,发送操作就变成非阻塞(或最多等待缓冲区腾出空位),goroutine 能立即继续执行并退出。
- 把
make(chan bool)改成make(chan bool, 1),两个 goroutine 都能完成c 并自然结束 - 缓冲大小不必精确匹配发送次数;设为 1 就足以打破同步阻塞链
- 注意:缓冲过大(如
make(chan int, 10000))可能掩盖设计问题,比如本该用 context 控制生命周期却靠堆内存硬扛
goroutine 无法被回收的其他常见场景
除了 channel 阻塞,还有几类典型泄漏点,都源于“goroutine 没有明确退出路径”:
- 无限循环里没加
select+ctx.Done()判断,例如for { doWork(); time.Sleep(...) } - 启动 goroutine 时捕获了大对象指针(如
go func() { use(r) }()),导致整个结构体无法被 GC,即使 goroutine 已退出 - 用
time.AfterFunc或time.Tick启动 goroutine,但没管理其取消逻辑,定时器持续触发新 goroutine - HTTP handler 中直接
go process(r),没做并发限制,请求洪峰时瞬间创建数万 goroutine
真正安全的 goroutine 生命周期控制依赖 context
缓冲 channel 只解决“单次通信后退出”的简单 case;复杂流程必须靠 context.Context 主动通知取消。
- 所有阻塞操作(
、<code>time.Sleep、http.Get)都应支持 context 取消,优先用ctx.Done()配合select - 不要依赖“goroutine 自己感知超时”,而是由父 goroutine 通过
ctx.WithTimeout或ctx.WithCancel统一控制 - 示例:用
select { case 替代裸 <code>,确保上下文取消时 goroutine 能及时退出
缓冲 channel 是 quick fix,context 才是正解;但最危险的其实是两者都不用——那种 goroutine 一旦启动,就只能等进程重启才能清理。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











