liveBook · Manning

Channel leak

As explained in Go in Practice, Second Edition

A channel leak is a failure to release an unneeded Go channel, causing it to remain allocated and consume system resources.

A channel leak occurs when an unneeded Go channel remains open and a related goroutine never returns, consuming resources without doing useful work. This commonly appears in long-running programs that repeatedly create channels and goroutines. section 5.3.2

Prevent leaks by coordinating shutdown:

  • Close channels safely and return from goroutines when their work ends. section 5.3.2
  • Avoid closing a channel from a receiver while a sender may still send; that causes a send-on-closed-channel panic. section 5.3.2
  • Use a separate notification channel to tell the sender when it should close the data channel and exit. section 5.3.2
Listing 5.8 Improper channel close
package main

import (
     "fmt"
     "time"
)

func main() {
     msg := make(chan string)
     until := time.After(5 * time.Second)
     go send(msg)                          #1
     for {                                   #2
            select {
            case m := <-msg:               #3
                    fmt.Println(m)
            case <-until:                                 #4
                    close(msg)                            #4
                    time.Sleep(500 * time.Millisecond)    #4
                    return                                #4
            } #4
     }
}

func send(ch chan string) {       #5
     for {
            ch <- "hello"
            time.Sleep(500 * time.Millisecond)
     }
}

Shows an improper timeout path that closes a channel while its sender continues writing. section 5.3.2

Listing 5.10 Using a close channel
package main

import (
    "log"
    "time"
)

func main() {
    msg := make(chan string) //        #1
    done := make(chan bool)  //     #2
    go send(msg, done) //             #3
    for {
        select {
        case m := <-msg: //        #4
            log.Println(m)
        case <-time.After(5 * time.Second): //      #5
            done <- true
            return
        }
    }
}
func send(ch chan<- string, done <-chan bool) {
    for {
        select {
        case <-done: //                                 #6
            log.Println("Done")
            close(ch)
            return
        default:
            ch <- "hello"           #7
            time.Sleep(500 * time.Millisecond) //       #8
        }
    }
}

Shows a close channel coordinating sender shutdown, data-channel closure, and goroutine return. section 5.3.2

How Go in Practice, Second Edition covers it

How deep it goes
Explains leak conditions, unsafe closure, panic behavior, and coordinated shutdown with runnable examples.
Examples
Uses timeout-driven programs demonstrating improper closure, sender-owned closure, and a separate shutdown channel.
What it assumes
Assumes familiarity with Go goroutines and channels while clarifying safe cleanup from the problem examples.
What you can do after
Diagnose channel leaks and apply coordinated shutdown so senders close channels and return safely.
How it connects
Connects channel leaks with goroutines, channel closing, timeouts, select, and resource consumption.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Practice, Second Edition. The section links point to the parts of the book it draws on.