具有监控存活的 goroutine 数量功能的 APM (Application Performance Monitoring) 应用程序性能监控可以轻松查出 goroutine 泄漏。例如 NewRelic APM 中 goroutine 的监控。
goroutine 泄漏会导致内存中存活的 goroutine 数量不断上升,直到服务宕机为止。因此,可以在代码部署之前,通过一些方法来检查程序中是否存在泄漏
泄漏检测
隶属于 Uber 公司的 Go 团队在 GitHub 开源了他们的 出来,一个与单元测试结合使用的工具。 goleak 可以监控当前测试代码中泄漏的 goroutine。下面有一个 goroutine 泄漏的例子:
测试代码:
运行结果中展示了 goroutine 的泄漏情况:
从报错信息中我们可以提取出两个有用的信息:
go test -trace trace.out之后,我们就可以从这些 trace 中获取到 goroutine 的详细执行情况。
到此,我们已经检测到了泄漏的 goroutine,并且知道了它详细的运行情况。现在,我们需要通过学习这个库的运行原理来了解这种检测方法的局限性。
运行原理
启用泄漏检测的唯一要求就是在测试代码结束之前,调用 goleak 库来检测泄漏的 goroutine。事实上,goleak 检测了所有的 goroutine 而不是只检测泄漏的 goroutine
goleak 运行结果中首先列出了所有存在的 goroutine,以下是运行结果的完成截图:
runtime.Stack之后,goleak 解析所有的 goroutine 出并通过以下规则过滤 go 标准库中产生的 goroutine:
- 由 go test 创建来运行测试逻辑的 goroutine。例如上图中的第二个 goroutine
- 当前运行的 goroutine,例如上图的第一个 goroutine
经过此次过滤后,如果没有剩余的 goroutine,则表示没有发生泄漏。但是 goleak 还是存在一下缺陷:
- 三方库或者运行在后台中,遗漏的 goroutine 将会造成虚假的结果(无 goroutine 泄漏)
- 如果在其他未使用 goleak 的测试代码中使用了 goroutine,那么泄漏结果也是错误的。如果这个 goroutine 一直运行到下次使用 goleak 的代码, 则结果也会被这个 goroutine 影响,发生错误。
goleak 库虽然不是完美的,但是了解其局限性和缺陷,也可以尽量避免因为 goroutine 泄漏,而要调试在生产环境中的代码。
net/httpafterTest本文由 原创编译, 荣誉推出