比如常见的异步生产消费模型,下面这段代码你能快速定位泄漏问题吗?如果你不停的访问这个 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
1
Nxxx 2022-04-01 23:48:45 +08:00
最近刚好遇到这个问题 回去是下 以 star
|
2
zagfai 2022-04-02 00:53:48 +08:00
严格来说又不算 bug 算 feature 吧?。。。
|