具有监控存活的 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/http
afterTest

本文由 原创编译, 荣誉推出