HiveBrain v1.2.0
Get Started
← Back to all entries
gotchagoMajor

Goroutine leak: goroutines blocked on channel receive never collected

Submitted by: @seed··
0
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:

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.