The Replacement Policy's Scan-Resistance Problem: Why LRU Falls Apart on Streaming Workloads

2026-06-12

LRU (Least Recently Used) sounds like the obvious cache replacement policy: throw out the line you haven't touched in the longest time. It works beautifully when your working set fits in cache. It catastrophically falls apart the moment your workload scans — touches a large array once, then moves on.

Here's the failure mode: imagine an L2 cache that holds 16 MB. Your hot working set is 12 MB and benefits enormously from caching. Then your program does memcpy over a 64 MB buffer. Every line in that 64 MB buffer enters L2, marked as "most recently used." LRU dutifully evicts your hot 12 MB to make room for streaming data that will never be touched again. After the memcpy, your hot data is gone, and the streaming data sits there cold until it ages out. This is called cache pollution, and it's why pure LRU lost its crown.

The fix is scan-resistance: don't immediately promote new lines to "most recently used." Instead, insert them near the eviction end of the LRU stack, and only promote them if they get a second hit. Lines that are touched once and never again get evicted quickly. Lines that prove themselves get protected. This is the core idea behind RRIP (Re-Reference Interval Prediction) and Intel's DRRIP, which ships in modern Xeon L3 caches.

In RRIP, each line gets a 2-bit counter (the "re-reference prediction value," or RRPV):

New lines are inserted with RRPV=2 — not RRPV=0. They have to earn promotion to RRPV=0 through a hit. On eviction, the cache scans for any line with RRPV=3; if none exists, it increments all RRPVs and tries again. This means scanned-once lines get evicted within roughly two passes, while reused lines stay protected.

Rule of thumb: If your workload's footprint exceeds your last-level cache by 2× or more and you see no reuse within that pass, you're paying for cache pollution on LRU. Use non-temporal stores (MOVNTDQ, vmovntps) or prefetchnta to bypass the cache entirely — you're telling the hardware "don't bother caching this, I won't be back." On modern Intel chips with DRRIP, the policy itself handles this gracefully, but explicit hints still help.

The deeper lesson: the "obvious" caching policy assumes recency predicts reuse. For scans, that assumption is exactly backwards — recency predicts uselessness.

Key Takeaway: Pure LRU treats every newly touched line as precious, which means a single large scan can wipe out a carefully built-up working set; modern caches use scan-resistant policies like RRIP that force new lines to earn their place before they're protected.

All newsletters