workshop private

← all creations

Belady

viz · created 2026-09-05

One reference string through two caches at once, k frames against k+1, where the containment strip underneath shows the inclusion property holding step after step under LRU — and breaking under FIFO, which is the door through which the bigger cache ends up faulting more than the smaller one.

algorithmsinterview-prepcanvas

Two caches, side by side, fed the same stream of page requests. The left one has k frames, the right one has k + 1. Everything else — the policy, the string, the order — is identical. The only question the piece asks is whether the right-hand cache faults fewer times than the left, and the answer under FIFO is: not always.

The default string is the one from Bélády, Nelson and Shedler’s 1969 paper — 1 2 3 4 1 2 5 1 2 3 4 5 — and under FIFO it takes 9 faults in three frames and 10 in four. Adding memory made it worse. That is Bélády’s anomaly, and the reason it is worth a picture rather than a sentence is that the sentence sounds like a typo.

What each band is

Everything that is a function of the step shares one x-axis, so a column is the same request whichever band you read it in.

The mechanism, which is the containment strip

The anomaly looks like a paradox until you watch the strip. Switch the policy to LRU and it stays solid green for the whole run: whatever three frames are holding, four frames are holding too. That is the inclusion property, and a policy that has it is called a stack algorithm. It makes the anomaly impossible for the boring reason — the bigger cache can only fault on a page the smaller one also lacks, so its fault set is a subset, request by request. LRU has it. OPT has it. FIFO does not, and the strip goes red the moment FIFO’s four-frame cache drops a page its three-frame cache is still holding.

That is the whole mechanism: the extra frame does not just add space, it changes the arrival order, and FIFO evicts on arrival order. A page that would have been evicted early in the small cache survives long enough in the big one to become the oldest thing there at exactly the wrong moment.

The strip also makes the weaker half of the claim visible, which most treatments skip. Run FIFO on a random string and you will often see the strip break with no anomaly in the totals at all — the story panel says so when it happens. Losing inclusion is necessary for the anomaly, not sufficient. It unlocks the door; it does not walk through it.

Is the classic string cherry-picked?

That is what the find an anomaly button answers, and the number it reports is the point. It searches uniform-random reference strings at your chosen capacity and stops at the first one where k + 1 frames faults more than k. Measured over 40 runs per capacity:

framesfoundmedian strings searched
2 vs 30 / 40— (80,000 exhausted, every time)
3 vs 440 / 40~600
4 vs 540 / 40~170
5 vs 640 / 40~110
6 vs 740 / 40~175

So: roughly one random string in a thousand at three against four, and closer to one in two hundred by six against seven. Rare enough that you will never trip over one while checking your own work; common enough that a fresh example is a few hundred tries away. Not cherry-picked — just not what anybody writes down.

The empty row is the other half of the answer. At two frames against three the search comes back empty every single time, at every seed, having burned the whole 80,000-string budget. The smallest counterexample anyone writes down is the 3-against-4 classic, and the search agrees with that.

The other streams

Reuse

src/belady.js is a framework-free ES module with no canvas and no timers:

Same trace-per-tick shape as collapse, rho, sift and window: the module produces frames, the demo draws them.

Gotchas