go是帶內存自動回收的特性,因此內存一般不會泄漏。但是Goroutine確存在泄漏的情況,同時泄漏的Goroutine引用的內存同樣無法被回收。
下面的程序中后台Goroutine向管道輸入自然數序列,main函數中輸出序列。但是當break跳出for循環的時候,后台Goroutine就處於無法被回收的狀態了。
func main() { ch := func() <-chan int { ch := make(chan int) go func() { for i := 0; ; i++ { ch <- i } } () return ch }() for v := range ch { fmt.Println(v) if v == 5 { break } } }
我們可以通過context包來避免這個問題:
func main() { ctx, cancel := context.WithCancel(context.Background()) ch := func(ctx context.Context) <-chan int { ch := make(chan int) go func() { for i := 0; ; i++ { select { case <- ctx.Done(): return case ch <- i: } } } () return ch }(ctx) for v := range ch { fmt.Println(v) if v == 5 { cancel() break } } }
當main函數在break跳出循環時,通過調用cancel()來通知后台Goroutine退出,這樣就避免了Goroutine的泄漏。