A channel leak occurs when an unneeded Go channel remains open and a related goroutine never returns, consuming resources without doing useful work. This commonly appears in long-running programs that repeatedly create channels and goroutines. section 5.3.2
Prevent leaks by coordinating shutdown:
- Close channels safely and return from goroutines when their work ends. section 5.3.2
- Avoid closing a channel from a receiver while a sender may still send; that causes a send-on-closed-channel panic. section 5.3.2
- Use a separate notification channel to tell the sender when it should close the data channel and exit. section 5.3.2
Listing 5.8 Improper channel close
package main
import (
"fmt"
"time"
)
func main() {
msg := make(chan string)
until := time.After(5 * time.Second)
go send(msg) #1
for { #2
select {
case m := <-msg: #3
fmt.Println(m)
case <-until: #4
close(msg) #4
time.Sleep(500 * time.Millisecond) #4
return #4
} #4
}
}
func send(ch chan string) { #5
for {
ch <- "hello"
time.Sleep(500 * time.Millisecond)
}
}
Shows an improper timeout path that closes a channel while its sender continues writing. section 5.3.2
Listing 5.10 Using a close channel
package main
import (
"log"
"time"
)
func main() {
msg := make(chan string) // #1
done := make(chan bool) // #2
go send(msg, done) // #3
for {
select {
case m := <-msg: // #4
log.Println(m)
case <-time.After(5 * time.Second): // #5
done <- true
return
}
}
}
func send(ch chan<- string, done <-chan bool) {
for {
select {
case <-done: // #6
log.Println("Done")
close(ch)
return
default:
ch <- "hello" #7
time.Sleep(500 * time.Millisecond) // #8
}
}
}
Shows a close channel coordinating sender shutdown, data-channel closure, and goroutine return. section 5.3.2
