比如常见的异步生产消费模型,下面这段代码你能快速定位泄漏问题吗?如果你不停的访问这个 3000 端口,网站会内存泄漏。
package main
import (
"fmt"
"net/http"
)
func main() {
_ = http.ListenAndServe(":3000", http.HandlerFunc(handle))
}
func handle(_ http.ResponseWriter, _ *http.Request) {
c := make(chan int)
go produce(c)
go consume(c)
}
func produce(c chan int) {
for i := range "..." {
c <- i
}
}
func consume(c chan int) {
for i := range c {
fmt.Println(i)
}
}
我们可以用 gotrace 来自动定位泄漏点,添加一个 main_test.go
文件:
package main
import (
"testing"
"github.com/ysmood/gotrace"
)
func TestHandle(t *testing.T) {
gotrace.CheckLeak(t, 0)
handle(nil, nil)
}
运行 GODEBUG="tracebackancestors=10" go test
,等待 3 秒后就可以看到打印信息如下:
--- FAIL: TestHandle (3.00s)
main_test.go:10: leaking goroutines: goroutine 6 [chan receive]:
play.consume(0x0)
/Users/ys/repos/play/default/main.go:25 +0x74
可以看到第 25 行的 range
卡住了,原因是 chan receive
,它在等待 c
的新消息,然而 produce 函数已经退出不会再往 c
里发布消息了。
修正的方法很多,比如把 produce 修改为:
func produce(c chan int) {
for i := range "..." {
c <- i
}
close(c)
}
再运行 go test
测试就立马成功结束了。
想了解更多 gotrace 用法可以移步 https://github.com/ysmood/gotrace
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.