Memcached Slab Allocator: Why Your 800-Byte Values Waste 40% of Memory
Memcached evicts items despite free RAM because its slab allocator rounds values to fixed chunk sizes. Learn to read stats slabs, spot per-class starvation, and use slab_automove or manual reassignment to reclaim wasted pages.
14 Aug 2026, 18:20 UTC

The Problem: Evictions Despite Free Memory
You're running Memcached with 4 GB allocated. stats shows 1.2 GB free, yet your application logs report SERVER_ERROR out of memory during peak traffic. The dashboard shows evictions climbing. Restarting the daemon clears the errors temporarily, but they return within hours.
This isn't a memory leak. It's how Memcached's slab allocator works: memory is divided into 1 MB pages, each carved into fixed-size chunks called slab classes. When your workload's value sizes don't align with those chunk sizes, you get internal fragmentation—wasted bytes inside every chunk—and per-class LRU eviction that ignores free pages in other classes.
How Slab Classes Create Waste
Memcached doesn't malloc per item. At startup it reserves memory in 1 MB pages. Each page is assigned to a slab class and sliced into equal chunks. The default growth factor (-f 1.25) produces chunk sizes like 96 B, 120 B, 152 B, 192 B, 240 B, 304 B, 384 B, 480 B, 600 B, 752 B, 944 B, 1184 B, and so on.
Every item (key + value + overhead ~50-60 bytes) is rounded up to the nearest chunk size. If your values average 800 bytes, the item lands in the 944-byte class. Each chunk wastes 144 bytes. A 1 MB page holds 1,081 chunks; 155 KB of that page is pure padding.
Worked Example: 800-Byte Values
Assume a workload storing 500,000 items with 800-byte values and 50-byte keys. Item size ≈ 850 bytes (key + value + flags + CAS + overhead). The allocator rounds to the 944-byte slab class.
| Metric | Value |
|---|---|
| Chunk size | 944 bytes |
| Items per 1 MB page | 1,081 |
| Used per page | 944 × 1,081 ≈ 1,020 KB |
| Wasted per page | ≈ 155 KB (13.2%) |
| Total pages for 500k items | 463 |
| Total memory consumed | 463 MB |
| Effective payload | 500,000 × 850 B ≈ 405 MB |
| Overhead ratio | ~14% |
Now imagine a second workload with 2 KB values. They land in the 2,048-byte class (2 KB chunks, 512 per page, zero waste). If the 800-byte workload fills its slab class first, new inserts trigger evictions only within that class, even though the 2 KB class has free pages. That's slab-class starvation.
Diagnosing with stats slabs
Run stats slabs on a staging instance under realistic load. Key columns:
chunk_size— the fixed size for that classtotal_pages— pages assigned to the classused_chunks/free_chunks— utilizationevicted/evicted_nonzero— evictions from this class
If you see a class with high evicted while other classes show free_chunks > 0, you have slab-class starvation. The fix isn't more RAM—it's moving pages between classes.
Fixing Starvation: slab_automove and Manual Reassignment
Memcached 1.5+ includes a background thread (slab_automove) that can shift free pages from underused classes to starved ones. Enable it at runtime:
echo "slab_automove 1" | nc localhost 11211
Mode 1 (conservative) moves pages only when a class has zero free chunks and another class has >2 free pages. Mode 2 (aggressive) moves more readily. Watch stats slabs after enabling; total_pages per class should shift toward the starved class.
For immediate relief, manually reassign a page:
echo "slabs reassign 12 15" | nc localhost 11211
This moves one page from class 12 to class 15. The daemon copies items to a new page in the target class, then frees the source page. Run during low traffic; the copy is synchronous and blocks the class briefly.
Trade-offs and Limitations
- Restart required for geometry changes. Changing the growth factor (
-f) or max item size (-I) requires a full restart and flushes the cache. Plan a cold-cache window. - Segmented LRU (1.5+) changes eviction dynamics. HOT/WARM/COLD queues plus
lru_crawlerandlru_maintainerthreads improve hit ratios but make per-class eviction less predictable. Verify behavior on your version. - Automove isn't instant. It runs every few seconds and moves one page at a time. Under sudden workload shifts, manual
slabs reassignmay be faster. - Key limit is hard. Keys >250 bytes are rejected; no runtime override.
Actionable Checklist
- Capture
stats slabstwice, 60 seconds apart, on staging. Diff theevictedcounters to find starved classes. - If evictions concentrate in one class while others have
free_chunks > 0, enableslab_automove 1and monitor for 30 minutes. - If automove doesn't keep up, schedule a manual
slabs reassignfrom a donor class during a maintenance window. - For chronic waste (like the 800-byte example), evaluate value compression (snappy, zstd) or a tuned
-f 1.15growth factor at next planned restart. - Set alerts on per-class eviction rate, not just global evictions.
The slab allocator is predictable once you see the numbers. Stop guessing at "out of memory" and start reading stats slabs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.