goleak 是当前事实上的标准协程泄漏检测工具,leaktest 非官方且未被主流项目采用;goleak.VerifyNone(t) 需在测试函数首行 defer 调用,于测试结束时比对快照,不支持真正实时函数内检测。

不能在函数内部实时检测协程泄漏——goleak 只能在测试结束时比对 goroutine 快照,没有运行时钩子或 API 支持函数级即时检测。
为什么 leaktest 不是官方或主流工具?
你提到的 leaktest 并非 Go 生态中广泛使用的标准工具。当前事实上的标准是 goleak(Uber 开源),而 leaktest 既不在 Go 官方库中,也未被主流项目(如 Kubernetes、etcd、Docker)采用。搜索 GitHub 或 pkg.go.dev,几乎找不到活跃维护的 leaktest 包。误用它可能导致:无法识别 Go 1.21+ 堆栈格式变化、缺少对 t.Parallel() 的正确处理、过滤规则失效。
goleak.VerifyNone(t) 是唯一可靠的函数级检测方式
它不是“在函数内检测”,而是“在测试函数退出前注册一个延迟检查”。实际检测发生在 t 生命周期结束、所有 defer 执行完毕之后。
- 必须写在测试函数第一行:
defergoleak.VerifyNone(t),否则可能漏掉提前启动的 goroutine - 仅对当前测试生效,不感知其他测试的 goroutine 状态
- 会捕获从该测试开始到结束新增的所有 goroutine,排除默认白名单(如
testing.RunTests、runtime.goexit) - 若测试中调用了
t.Parallel(),该 goroutine 可能仍在运行,VerifyNone会误报;此时应改用VerifyTestMain
真正需要“函数内感知”时,只能手动标记 + 事后验证
没有魔法函数能告诉你“此刻有没有泄漏”,但你可以控制起点和终点:
- 在函数入口调用
stack.All()(需引入go.uber.org/goleak/internal/stack)获取 baseline 快照 - 在函数出口再次调用
stack.All(),手动比对新增 goroutine 的createdBy和state - 注意:这绕过了
goleak的过滤逻辑,容易把net/http.serverHandler这类正常长期 goroutine 当作泄漏 - 更现实的做法是:把疑似泄漏的函数封装成独立测试,用
VerifyNone覆盖,而非强行塞进业务函数里
真正难的不是“怎么调 API”,而是理解 goroutine 泄漏的本质——它永远是**跨生命周期的资源残留**。试图在单个函数内“实时检测”,就像想用体温计测地震:工具不对,时机也不对。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











