Skip to content

Leaked tasks

Category: Hazards · Status: stub · Lessons: chapter 06, Async (planned)

One line: A thread, goroutine or task blocked for ever on something nobody will provide, holding its memory until the process ends.

Also called: goroutine leak, thread leak, memory leak, zombie thread.

How it connects

flowchart LR
  n_cancellation["Cancellation"]
  n_task_leak["Leaked tasks"]
  n_liveness_failure["Liveness failure"]
  n_structured_concurrency["Structured concurrency"]
  n_cancellation -->|prevents| n_task_leak
  n_structured_concurrency -->|prevents| n_task_leak
  n_task_leak -->|is a| n_liveness_failure
  classDef center stroke-width:3px
  class n_task_leak center
  classDef outside stroke-dasharray: 4 3
  class n_cancellation,n_liveness_failure,n_structured_concurrency outside

In each language

Rust JoinHandle detaches its thread when dropped, and mem::forget is safe: Rust does not guarantee that destructors run
Go context: failing to call a CancelFunc leaks the child context, and go vet checks for it; runtime/pprof lists a goroutineleak profile
C++ Destroying a joinable std::thread calls std::terminate; std::jthread joins on destruction
Java ExecutorService: an unused executor should be shut down to allow reclamation of its resources
Python asyncio.create_task needs a strong reference kept to the task; asyncio.TaskGroup keeps one and awaits every task
Kotlin GlobalScope: a coroutine that is never cancelled or resumed can be a resource leak, so tie coroutines to a lifecycle
The operating system pthread_join(3) ↗: a joinable thread that nobody joins becomes a zombie thread holding system resources

Where to read more