Visual walkthrough — Replacement policies (LRU, FIFO, random)
This page builds the three replacement policies — LRU, FIFO, and Random — from nothing but a row of boxes. We will watch each policy make its choice, one access at a time, and then watch FIFO do something that feels impossible — get worse when you give it more room. Every symbol is earned before it appears.
Step 1 — The shelf, the slots, and one word we will reuse everywhere
WHAT. Draw a set of the cache as a row of boxes. Each box is called a way — it is one physical slot that can hold one block (a chunk of memory the size the cache moves around). A set with boxes is ==-way associative==. Here .
WHY. Every policy we study is just a different answer to one question: "the four boxes are full and block wants in — which box gets emptied?" We cannot ask that question until we can see the four boxes.
PICTURE (Figure s01). Four empty boxes labelled way 0 … way 3, with the incoming stream drawn as an orange queue above them and a "time →" arrow. This is the access sequence, the order the processor asks for blocks. We will feed this same sequence to LRU and FIFO so the difference is purely the policy.

A single request is a hit if the block is already in a box, or a miss if it is not — and a miss on a full set is what forces an eviction (emptying a box). See 5.4.01-Cache-organizationand-addressing for how the address chooses which set.
Step 2 — LRU's ruler: the recency counter, and the exact order of operations
WHAT. Give every occupied box a small number written under it: its recency. Recency means "just touched, the freshest block." A bigger number means "staler." We update it with one rule, and — crucially — we fix the exact sequence in which the miss is handled.
WHY. LRU (Least Recently Used) wants to throw away the block nobody has touched in the longest time. To do that it needs a way to measure "how long ago" — recency is that ruler. Why measure the past at all? Because of temporal locality: a block used recently is likely to be used again, so the least recently used is the safest to discard. But a ruler alone is not a policy: we must also say when we read it, when we age the counters, and what number the brand-new block gets.
PICTURE (Figure s02). Read the update rule right off the boxes, then read the operational recipe below it.

Step 3 — Watch LRU run the sequence A B C D A E
WHAT. Feed to the four boxes, drawing the recency number under each box after each access is fully handled (following the evict-then-update recipe of Step 2).
WHY. This is the payoff of Step 2 — we see the counters age, the hit on reset to , the victim chosen before the new block's counter is written, and the new block enter with recency . Note the first four accesses just fill empty ways; no eviction happens until the set is full.
PICTURE (Figure s03). Follow the coloured strip. The star marks the eviction.
| Access | Boxes (way0…way3) | Recency after | What happened |
|---|---|---|---|
| miss, empty way 0 → load , set its recency 0 | |||
| miss, empty way 1 → load (rec 0), ages to 1 | |||
| miss, empty way 2 → load (rec 0), age | |||
| miss, empty way 3 → load (rec 0), set now full | |||
| hit on → reset to 0, others age | |||
| miss, full → evict , load (rec 0), rest age |
Reading the last row carefully (this is the fix). Just before handling , the recencies are . Following the recipe:
- Choose the victim first from these current values: the maximum is , so ==LRU evicts == (way 1). The recent hit on saved it.
- Then load into way 1 and apply the update: gets recency ; every other box ages , so , , .
That gives the final row , i.e. across ways . (The previous draft wrote ; that would only be correct under an "update-then-evict" ordering, which we explicitly rejected — we age the survivors after choosing the victim, so , being older than , ends up the stalest survivor at .)

Step 4 — FIFO's ruler: a single pointer, and hits change nothing
WHAT. Throw away all four recency counters. Keep one number for the whole set: the queue pointer, written , which just remembers "which box gets emptied next." It starts at on a fresh, empty set — the pointer begins at way 0.
WHY. FIFO (First-In First-Out) evicts by arrival order — first block in is the first block out, like a lunch queue. It never looks at whether a block was used again. Why would anyone want a policy that ignores hits? Cost: FIFO needs only bits per set instead of a counter per box — for that is a single 2-bit number.
PICTURE (Figure s04). The pointer sweeps in a circle around the four boxes.

Step 5 — Watch FIFO run the same sequence A B C D A E
WHAT. Same input, same boxes, but now the only state is the arrow, starting at .
WHY. Running the identical stream through both policies isolates the difference to one decision. Watch the hit on do nothing.
PICTURE (Figure s05). The arrow is the orange marker; the star is the eviction.
| Access | Boxes | QueuePtr after | What happened |
|---|---|---|---|
| 1 | miss, load into empty way 0, arrow steps →1 | ||
| 2 | miss, load empty way 1, arrow →2 | ||
| 3 | miss, load empty way 2, arrow →3 | ||
| 0 | miss, load empty way 3, arrow wraps →0 | ||
| 0 | hit on — arrow frozen, nothing moves | ||
| 1 | miss, set full, arrow=0 → evict way 0 (), load , arrow →1 |
Which box died? The arrow sat at way 0, which held . So ==FIFO evicts == — the very block LRU just saved. FIFO never noticed the recent hit. Notice the pointer advanced on all five loads (the four fills and the eviction) but stood still on the one hit — exactly the rule in Step 4.

Step 6 — The third policy: Random, no ruler at all
WHAT. Random replacement keeps no history — no recency counters, no queue pointer. On a miss into a full set it picks a victim uniformly at random (every box equally likely) and overwrites it. On a miss with an empty way it still just fills the lowest empty way (the shared insertion rule of Step 1); only when the set is full does randomness kick in. Hits do nothing.
WHY. When you cannot afford to predict the future, you refuse to guess and flip a coin. This is cheaper than both alternatives — a tiny pseudorandom bit source, zero per-block state — and it is immune to the pathological patterns that trap FIFO (Step 8), because it has no rhythm for a pattern to fight against.
PICTURE (Figure s06). Four full boxes; a spinner points to whichever box the coin flips choose. On the same stream, Random might evict any of on the miss — each with probability . There is no single "the answer": that is the whole point.

Step 7 — A yardstick so we can compare miss counts
WHAT. Define miss rate plainly: the fraction of accesses that were misses. And place it inside the cost of memory.
WHY. We keep saying one policy is "better." Better means fewer misses, because misses are slow. This step gives us the yardstick before the finale.
PICTURE (Figure s07). A bar showing hit time as a short green segment and miss penalty as a long red one; miss rate is how often you pay the red one.

Naively you'd expect: more boxes → more blocks kept → fewer misses. For LRU that is guaranteed true — and the reason has a name we define now, before the anomaly, because it is the whole explanation.
Step 8 — Belady's Anomaly, 3 frames: 9 misses
WHAT. Use a fully-associative FIFO (as just defined: one big pool of frames, any block in any frame) with the classic stream and three frames. Count misses.
WHY. This is the setup half of the anomaly. We need the 3-frame count first so we have something to compare the 4-frame count against.
PICTURE (Figure s08). Twelve columns, each showing the hit/miss verdict after that access; misses marked in red.
Tracing FIFO (fill empty frames first, then evict oldest arrival; hits don't reorder):
| step | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hit/miss | M | M | M | M | M | M | M | H | H | M | M | H |
That is 9 misses out of 12. The two hits on and near the end are what save it.

Step 9 — Belady's Anomaly, 4 frames: 10 misses (the impossible-feeling result)
WHAT. Same stream, same fully-associative FIFO, now with four frames. Count misses again.
WHY. We added capacity — one more frame — expecting fewer misses. Watch it get worse. This is the degenerate case that kills the "bigger is always better" intuition, and it is possible precisely because FIFO is not a stack algorithm (Step 7).
PICTURE (Figure s09). Same twelve columns, one extra frame; the extra room shifts which block is oldest at each eviction, so blocks get thrown out right before they're reused.
| step | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hit/miss | M | M | M | M | H | H | M | M | M | M | M | M |
That is 10 misses — one more than with three frames.

The one-picture summary
WHAT. One figure stacking all three verdicts: the same stream, LRU vs FIFO vs Random victims side by side, plus the anomaly bars .
WHY. Everything on this page reduces to two facts — what ruler each policy uses, and what happens when the ruler ignores usage.

Recall Feynman retelling — say it back in plain words
Picture a shelf of four slots. While the shelf still has empty slots, every policy does the same boring thing: drop the new book into the next empty slot. The interesting decision only happens once the shelf is full and a new book arrives — one book must fall off.
LRU writes a little "last touched" number under every book. When a miss forces an eviction, it first reads those numbers and picks the book ignored longest, then loads the newcomer into that spot and stamps it fresh (number 0) while every other book ages by one. Re-reading a book resets its number, so re-reading protects it. In our run, re-reading meant (untouched longest) fell off — and afterward , the older survivor, became the stalest.
FIFO is lazier and cheaper: it keeps one arrow that just remembers whose turn it is to leave, going strictly by arrival order. The arrow starts at slot 0 and steps forward every time a book is loaded, wrapping around the shelf in a circle; re-reading a book does nothing to it. So in the exact same run, — the book we'd just re-read — got shoved off, because it arrived first.
Random keeps no notes at all: when the shelf is full it flips a coin and evicts whatever slot the coin names. Cheapest of all, occasionally unlucky, but impossible to trap.
Then the twist: with FIFO, giving the shelf a fifth slot made it drop more books (10 instead of 9) on a nasty repeating stream, because the extra slot shifted the arrow's rhythm so books got tossed just before they were wanted again. That's Belady's Anomaly. LRU can never misbehave that way — it is a "stack algorithm," meaning a bigger cache always keeps everything the smaller one kept — which is exactly why hardware leans on LRU-style rules despite their higher cost.
One line: LRU measures usage (safe, expensive); FIFO measures only arrival (cheap, trickable into getting worse with more memory); Random measures nothing (cheapest, coin-flip).
Recall Quick self-test
While the set still has empty ways, what does each policy do on a miss? ::: The same thing — fill the lowest-numbered empty way; no eviction. The policies only differ once the set is full. On an LRU full-set miss, do we choose the victim before or after writing the new block's recency? ::: Before — evict-then-update: read recencies, pick the max as victim, load the new block, then set it to 0 and age the survivors. What recency does a freshly loaded block get under LRU? ::: 0 — it was just accessed by definition. After the hit on in step 5, which block does FIFO evict on the next miss, and why? ::: (way 0) — the queue pointer sat at 0 and FIFO ignores the hit; arrival order alone decides. Why can LRU never show Belady's Anomaly? ::: LRU is a stack algorithm — its size- contents are always a subset of its size- contents, so more capacity can only remove misses, never add them. In A,B,C,D,A,E which block does LRU evict, and why not ? ::: ; the hit on reset 's recency to 0, making (recency 3) the least recently used. On the same stream, which block does Random evict on the miss? ::: Any of , each with probability — Random keeps no history, so there is no single answer.
Related depth: exact vs pseudo-LRU cost trade-offs tie into Cache-conscious-programming; policies interact with 5.4.03-Write-policies-(write-through,-write-back), 5.4.06-Cache-coherence-protocols, and reappear for page frames in 5.5.02-Virtual-memory-and-TLBs.