最近线上一个模块有内存泄漏,加了http pprof后,发现goroutine一直在增长,怀疑是goroutine泄漏导致的内存泄漏。于是死看代码,发现以下代码片段可能存在问题:
//goroutine
...
for{
select {
case ...
...
case ...
...
case <- exitChan:
break;
}
}
代码逻辑中,当socket关闭的时候会往exitChan发送数据,这个时候以上代码中的goroutine就需要跳出for循环,结束该goroutine。
问题就出在break上,这里的break是跳出case,还是跳出for?翻书,select-case没有break,所以我应该是写代码的时候以为这个break会跳出for循环。不能确认,那就写个代码测试一下。
package main
import (
"fmt"
"time"
)
var exitChan chan bool
func Waiting1(){
defer func(){
fmt.Println("waiting1 exit")
}()
//do someting
time.Sleep(time.Second *10)
exitChan <- true
}
func Waiting2(){
defer func(){
fmt.Println("waiting2 exit")
}()
for{
select {
case <-time.After(time.Second * 2):
fmt.Println("tick event...")
case <- exitChan:
fmt.Println("exit event...")
break
}
}
}
func main(){
exitChan = make(chan bool)
go Waiting1()
go Waiting2()
<- time.After(time.Second * 60)
fmt.Println("main return")
}
运行结果告诉我,select-case下的break果然只是跳出了select的分支,跟C语言中的switch-case一样。只不过C语言中,明确要求要break,而Go则没有要求。
所以,这回stupid了一回,赶紧检查一下其他代码,发现其他select-case的分支,如果要跳出for,都是用的return。可能当时写代码的时候脑袋进了水吧…
最后
以上就是义气板栗最近收集整理的关于select case break引发的血案的全部内容,更多相关select内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复