On this page

Date
2026-07-15
Read
2 min
Topic
rust
rust · concurrency

Reclaiming memory: hazard pointers vs epochs

2026-07-152 min readrust

The queue from part one works — until you try to free a popped node. Who guarantees no other thread still holds a pointer to it? That's the memory reclamation problem, and it has two classic answers.

Hazard pointers

Each thread publishes the pointers it's currently dereferencing into a shared, per-thread "hazard" slot. A node can only be freed once no hazard slot references it.

The trade-off

Hazard pointers give tight, predictable memory bounds — at most O(threads × K) unreclaimed nodes. The cost is a memory fence on every access to publish the hazard, which hurts read-heavy workloads.

Epoch-based reclamation

Threads advance through global epochs. Retired nodes are stashed in per-epoch bags and only freed once every thread has moved two epochs past the retirement.

reclaim.rs
1let guard = epoch::pin();              // enter the current epoch2let shared = self.head.load(Acquire, &guard);3guard.defer_destroy(shared);           // freed once all threads advance
🦀
Ferris' hot tip

Epoch reclamation is what crossbeam-epoch uses under the hood. Pinning is cheap (a single atomic), which is why it usually wins for general-purpose structures.

Which one?

Hazard pointers
owns: bounded memory
read fence per accesstight memory bound
Best when you must cap unreclaimed memory hard — allocators, embedded systems.
Epoch-based
owns: throughput
cheap pinningdeferred batch free
Best for general-purpose structures where a brief reclamation lag is fine.

The short version: epochs for throughput, hazard pointers for bounded memory.

Comments
Loading comments…