How does Memcached handle lazy expiration vs active reclamation?

Memcached uses lazy expiration as its primary mechanism for handling expired keys, delaying memory cleanup until an item is explicitly requested, while relying on active memory reclamation strategies like LRU eviction and background crawler threads when available RAM is needed for new items.

Lazy Expiration Mechanics

Lazy expiration (also referred to as passive deletion) means Memcached does not continuously scan memory to remove expired key-value pairs. Instead, it evaluates an item's time-to-live (TTL) timestamp only when a client attempts to read or update that specific key:

  • On Access: When a get command targets an expired key, Memcached identifies that the expiration timestamp has passed, frees the associated chunk, and returns a cache miss to the client.
  • Low Overhead: This approach guarantees \(O(1)\) operations because no dedicated background cycles are spent tracking or purging keys that are never read again.
  • Trade-off: Expired keys that are never accessed again continue to occupy memory chunks until active reclamation measures take over.

Active Memory Reclamation Mechanisms

When memory allocated to a slab class is exhausted, Memcached relies on active reclamation mechanisms to free up space:

1. LRU Eviction

When storing a new key in a full slab class, Memcached reclaims space using a Least Recently Used (LRU) algorithm. If no unallocated chunks or expired items are found, it evicts the tail item from the LRU list within that specific slab class—even if that item's TTL has not yet expired.

2. LRU Crawler

To prevent expired items from remaining idle indefinitely in memory, modern versions of Memcached feature an asynchronous background thread called the LRU Crawler. The crawler crawls memory structures, identifies items whose TTLs have elapsed, and frees those memory chunks proactively without requiring a client read request.

Comparison Summary

Feature Lazy Expiration Active Reclamation (LRU & Crawler)
Trigger Client read/write operation on a specific key Allocation requests when memory is full or background thread execution
CPU Cost Negligible \(O(1)\) lookup cost during access Low background overhead or inline eviction handling
Memory Impact Expired keys linger until touched or evicted Frees memory chunks immediately for new allocations
Target Data Only expired keys Expired keys and least recently used valid keys