The Maple Tree: How Linux Replaced the VMA Red-Black Tree With a Range-Optimized B-Tree

2026-08-23

For decades, every process's virtual memory areas (VMAs) — the ranges returned by mmap(), the stack, heap, and every shared library segment — were stored in a red-black tree keyed by start address, plus a linked list for in-order traversal, plus an mmap_sem to protect it all. Linux 6.1 (2022) tore this out and replaced it with the maple tree: a range-based, cache-friendly, RCU-safe B-tree.

The old design had three problems. First, an rbtree node is small (~40 bytes) but scattered — walking it thrashes cache. Second, the tree stored points, not ranges, so finding "which VMA contains address X" required a walk plus a boundary check. Third, the mmap_sem was a per-process rwsem: any two threads calling mmap() or taking a page fault serialized on it. A 64-thread process with heavy fault activity would spend >30% of CPU spinning on that lock.

The maple tree fixes all three. It's a B-tree with wide nodes (up to 16 slots per internal node, storing pivots between ranges). A single 256-byte cache line holds an entire node — one cache miss finds the VMA where a linear scan of an rbtree took 5-6. It's range-native: each slot represents [start, end), so lookup by address is a single descent with no boundary re-check. And it supports RCU readers — page faults can walk it lock-free, taking a spinlock only for the rare write.

Real-world impact: The Android team benchmarked app startup on a Pixel: cold-start page-fault-heavy phases saw 30-60% reduction in mmap_lock contention. Redis with 64 threads doing concurrent MADV_DONTNEED dropped from ~1.2M ops/sec to ~2.8M ops/sec on the same hardware. Chromium's renderer processes, which typically have 300+ VMAs and heavy fault activity, saw measurable page-fault latency reduction at p99.

Rule of thumb for VMA count: A "small" process has ~50 VMAs, a browser tab renderer ~300, a JVM ~500-800, a game with lots of mmap'd assets can hit 5000+. Rbtree walk cost was O(log n) but with a large constant (~7 cache misses at n=500). Maple tree: ~2 cache misses at n=500, ~3 at n=5000. The break-even was near n=20.

You can see the tree in action: cat /proc/self/maps | wc -l shows your VMA count. If it's over a few hundred and you're on kernel <6.1, upgrading is a free perf win with zero code changes.

Key Takeaway: Linux 6.1 replaced the 20-year-old VMA rbtree with a range-native, cache-dense, RCU-readable B-tree, dramatically reducing mmap_lock contention on fault-heavy multithreaded workloads without any user-space changes.

All newsletters