What is a goroutine leak? Give common causes.
Question 162MediumGo 1.22 to 1.25
A goroutine leak is a goroutine that stays blocked forever, or runs forever, after its work no longer matters. It keeps its stack and everything that stack references, so the GC cannot free that memory. Goroutines are never garbage collected. Memory and NumGoroutine keep growing until the process runs out of memory.
Classic causes:
- Sending on an unbuffered channel nobody reads, often a result channel after the caller has timed out and returned.
- Receiving from a channel that is never closed, for example
for v := range chwhen the producer forgetsclose. - No cancellation path: a worker loop that never checks
ctx.Done(). time.Tickerloops with no exit condition. Also HTTP response bodies that are never closed.- Deadlock between two goroutines while the rest of the program keeps running. The runtime detects deadlock only when all goroutines are blocked.
// Leaky: if ctx times out first, the goroutine blocks on send forever.
func fetch(ctx context.Context) (string, error) {
ch := make(chan string) // fix: make(chan string, 1)
go func() { ch <- slowCall() }()
select {
case v := <-ch:
return v, nil
case <-ctx.Done():
return "", ctx.Err()
}
}More on Goroutines & the Scheduler
- Q160What does runtime.Gosched do and when (if ever) should you use it?
- Q161What does runtime.LockOSThread do and when is it needed?
- Q163How do you detect and debug goroutine leaks in production and tests?
- Q164How many goroutines can a Go program run? How do you bound them?
- Q165Why doesn't Go expose goroutine IDs, and how do you "kill" a goroutine?
- Q166What happens when main returns while other goroutines are still running? What does this print?