gotchagoMajor
Goroutine leak: goroutines blocked on channel receive never collected
Viewed 0 times
goroutine leakblocked goroutinechannel never closedgoleakcontext cancelconcurrency leak
Problem
Goroutines blocked waiting on a channel that is never closed or written to stay alive forever. The Go runtime has no garbage collection for blocked goroutines, so memory and resources leak silently.
Solution
Always ensure every goroutine has an exit path. Use a done channel or context cancellation:
Detect leaks with goleak in tests:
func worker(ctx context.Context, jobs <-chan Job) {
for {
select {
case <-ctx.Done():
return // exits when context is cancelled
case j, ok := <-jobs:
if !ok {
return // exits when channel is closed
}
process(j)
}
}
}Detect leaks with goleak in tests:
import "go.uber.org/goleak"
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
}Why
The Go scheduler parks goroutines blocked on channel operations. Without an explicit wakeup (send, close, or select with context), they never unpark. The GC cannot collect goroutines that are still reachable through channel references.
Gotchas
- A channel with no remaining senders and no close call will block receivers forever
- Goroutines started in tests that outlive the test cause goleak failures in later tests
- HTTP handler goroutines can leak if a downstream call has no timeout and the client disconnects
Revisions (0)
No revisions yet.