Go

Goroutine Leak Prevention

admin by @admin ADMIN
5d ago
May 31, 2026
Public
0 0 up · 0 down Sign in to vote
A goroutine that's blocked forever on a channel send/receive leaks — it's never garbage-collected. Always pair channels with `select { case <-ctx.Done(): return }` to give them an exit path.
Go
Raw
package main

import (
    "context"
    "fmt"
    "time"
)

// ❌ Leak risk — if no one ever receives, this goroutine lives forever
func leakyProducer(ch chan<- int) {
    ch <- 42                                       // blocks if buffer is full / no receiver
}

// ✓ Safe — give the goroutine an escape via the context
func safeProducer(ctx context.Context, ch chan<- int) {
    select {
    case ch <- 42:
        // sent successfully
    case <-ctx.Done():
        return                                     // exit on cancellation
    }
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
    defer cancel()

    ch := make(chan int)                          // unbuffered — no receiver yet

    go safeProducer(ctx, ch)
    time.Sleep(200 * time.Millisecond)
    fmt.Println("producer exited cleanly via ctx")

    // Run with `go test -race` to catch leaks; also try `runtime.NumGoroutine()`.
}
Tags

Save your own code snippets

Create a free account and build your private vault. Share publicly whenever you want.