内存泄露概念
如果你启动了一个 goroutine,但并没有符合预期的退出,直到程序结束,此goroutine才退出,这种情况就是 goroutine 泄露。当 goroutine 泄露发生时,该 goroutine 的栈(一般 2k 内存空间起)一直被占用不能释放,goroutine 里的函数在堆上申请的空间也不能被 垃圾回收器 回收。这样,在程序运行期间,内存占用持续升高,可用内存越来也少,最终将导致系统崩溃。
GOROUTINE终止场景
- 当一个goroutine完成它的工作
- 由于发生了没有处理的错误
- 有其他的协程告诉它终止
当三者都没有发生时,就会导致goroutine无法退出终止,gc无法回收,导致内存泄露。
内存泄露具体场景
channel阻塞:无缓存channel中只读不写,或者值写不读,会引起goroutine阻塞,无法退出和终止。
goroutine中出现死循环,无法退出,终止。如:
- unbuffered channel只读不写
c := make(chan int)
go func() {
v := <-c
fmt.Println("this v : %v", v)
- unbuffered channel只写不读
c := make(chan int)
go func() {
c <- 8
fmt.Println("only write do not read .")
}()
- 向一个已满的unbuffered channel只写不读
- select语句没有命中任何候选分支且没有默认分支
intChans := [3]chan int{
make(chan int, 1),
make(chan int, 1),
make(chan int, 1),
}
index := 2
fmt.Printf("index : %d \n", index)
intChans[index] <- index
select {
case <-intChans[0]:
fmt.Println("intChans 0 case select .")
case <-intChans[1]:
fmt.Println("intChans 1 case select .")
}
- goroutine进入死循环,导致无法退出终止
for {
fmt.Println("qqqq")
time.Sleep(2*time.Second)
}