What are LRU, LFU, and FIFO cache eviction strategies?
Cache eviction policies determine which item is removed when the cache is full and a new item must be inserted. The right policy depends on the access pattern of the workload.
**FIFO (First In, First Out)** evicts the oldest item by insertion order, regardless of access frequency or recency. It is the simplest to implement (a queue) but performs poorly for workloads with a stable working set — an item inserted long ago but accessed frequently will be evicted simply because it was inserted first.
**LRU (Least Recently Used)** evicts the item that was accessed least recently. The intuition is temporal locality: if you used something recently, you are likely to use it again soon. LRU is the most commonly deployed policy (Redis default, CPU hardware caches) because it works well for workloads with a temporal locality pattern. The standard implementation uses a doubly-linked list combined with a hash map, giving O(1) get and put. The limitation is that a single sequential scan (e.g., a large batch job reading unique keys) can flush the entire cache — an effect called **cache pollution**.
**LFU (Least Frequently Used)** evicts the item accessed the fewest times. This suits stable, long-lived working sets where some items are permanently hot (home page, popular product). A naive implementation requires counting accesses per key and finding the minimum — O(log n) with a min-heap. An O(1) implementation exists using two hash maps and a doubly-linked list of frequency buckets (Aho et al.). The weakness of LFU is the **aging problem**: an item accessed 1000 times last week but never since will have a very high count and resist eviction even when it is no longer relevant. LFU-with-decay (dividing counts periodically) or Window-TinyLFU (used by Caffeine, the Java cache, and adopted by Redis's LFU mode) addresses this with a sketch-based frequency estimator plus a recency window.
**LRU vs. LFU in practice**: use LRU for general-purpose caches with temporal locality. Use LFU (or W-TinyLFU) when the access distribution is highly skewed and the hot set is stable — content delivery caches, DNS caches, read-heavy database query caches. Redis supports both (`allkeys-lru` and `allkeys-lfu` maxmemory policies). Memcached uses a segmented LRU variant.
Correctly describes what each policy evicts and the basic implementation for LRU. May not discuss the aging problem in LFU or cache pollution in LRU.
Describes the O(1) LRU implementation detail (hashmap + doubly-linked list), explains the LFU aging problem and how W-TinyLFU solves it, names real systems using each policy, and can advise when to choose each based on access pattern characteristics.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment