Go

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 ch when the producer forgets close.
  • No cancellation path: a worker loop that never checks ctx.Done().
  • time.Ticker loops 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

All 35 Goroutines & the Scheduler questions