Kernel Same-page Merging (KSM)
Deduplicating identical memory pages
What Is KSM?
KSM scans memory for pages with identical content and merges them into a single copy-on-write (COW) page. When multiple processes have the same data in memory, KSM saves RAM by keeping only one copy.
Before KSM:
Process A Process B Process C
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Page X │ │ Page X │ │ Page X │
│ (same │ │ (same │ │ (same │
│ content)│ │ content)│ │ content)│
└─────────┘ └─────────┘ └─────────┘
3 pages = 12KB
After KSM:
Process A Process B Process C
│ │ │
└──────────────────┼──────────────────┘
│
▼
┌─────────┐
│ Page X │ (shared, COW)
│ │
└─────────┘
1 page = 4KB (saved 8KB)
Why KSM?
The Virtualization Use Case
KSM was designed for virtual machines. Multiple VMs often run identical operating systems:
| Scenario | VMs | Potential Sharing |
|---|---|---|
| 10 identical Linux VMs | 10 | Kernel, libraries, common data |
| Development cluster | 50 | Base OS, toolchains |
| VDI (Virtual Desktop) | 100+ | Windows, Office, browsers |
Without KSM: 10 VMs × 2GB = 20GB RAM With KSM: Shared pages reduce to ~8GB (varies by workload)
Beyond VMs
KSM also helps: - Containers with shared base images - Multiple instances of the same application - Fork-heavy workloads
How KSM Works
The ksmd Daemon
A kernel thread (ksmd) continuously scans memory:
ksmd loop:
│
├── Scan pages marked for merging
│
├── Hash page content
│
├── Look for matching hash in stable/unstable trees
│
├── If match: verify byte-by-byte, merge pages
│
└── Sleep, repeat
Two-Tree Structure
KSM uses two red-black trees:
Stable tree: Contains merged (shared) pages - Pages already deduplicated - Searched first for matches
Unstable tree: Contains candidate pages - Pages seen once, waiting for a match - Rebuilt each scan cycle
New page arrives
│
v
Search stable tree ──── Match? ──── Yes ──► Merge with stable page
│ │
No │
│ │
v │
Search unstable tree ── Match? ──── Yes ──► Merge both, add to stable
│ │
No │
│ │
v │
Add to unstable tree │
│ │
└───────────────────────────────────────────┘
Copy-on-Write
Merged pages are marked COW. If any process writes to the page:
- Page fault occurs
- Kernel copies page for the writer
- Writer gets private copy
- Other processes keep shared page
Enabling KSM
For Applications
Applications must explicitly mark memory for KSM scanning:
#include <sys/mman.h>
void *ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
/* Enable KSM scanning for this region */
madvise(ptr, size, MADV_MERGEABLE);
/* Disable KSM scanning */
madvise(ptr, size, MADV_UNMERGEABLE);
For QEMU/KVM
QEMU enables KSM for guest memory by default (can be disabled with -machine mem-merge=off).
System-Wide Control
# Enable/disable ksmd
echo 1 > /sys/kernel/mm/ksm/run # Start scanning
echo 0 > /sys/kernel/mm/ksm/run # Stop scanning
echo 2 > /sys/kernel/mm/ksm/run # Stop and unmerge all
# Check if running
cat /sys/kernel/mm/ksm/run
Configuration
Scan Rate
Defaults documented in the KSM admin guide:
# Pages to scan per cycle
cat /sys/kernel/mm/ksm/pages_to_scan
echo 100 > /sys/kernel/mm/ksm/pages_to_scan # Default: 100
# Sleep between cycles (milliseconds)
cat /sys/kernel/mm/ksm/sleep_millisecs
echo 20 > /sys/kernel/mm/ksm/sleep_millisecs # Default: 20
Higher pages_to_scan + lower sleep_millisecs = faster merging but more CPU.
Merge Behavior
# Merge pages across NUMA nodes? (0=no, 1=yes)
cat /sys/kernel/mm/ksm/merge_across_nodes
# Default: 1 (merges across nodes)
# Set to 0 for NUMA-aware workloads
# Maximum merged pages (0=unlimited)
cat /sys/kernel/mm/ksm/max_page_sharing
# Limits how many processes share one page
Monitoring
KSM Statistics
# Pages currently shared (deduplicated)
cat /sys/kernel/mm/ksm/pages_shared
# Total references to shared pages
cat /sys/kernel/mm/ksm/pages_sharing
# Memory saved = (pages_sharing - pages_shared) × 4KB
# Unstable tree size
cat /sys/kernel/mm/ksm/pages_unshared
# Pages that can't be merged (volatile)
cat /sys/kernel/mm/ksm/pages_volatile
# Full scans completed
cat /sys/kernel/mm/ksm/full_scans
Calculating Savings
#!/bin/bash
shared=$(cat /sys/kernel/mm/ksm/pages_shared)
sharing=$(cat /sys/kernel/mm/ksm/pages_sharing)
saved=$(( (sharing - shared) * 4 )) # KB saved
echo "KSM saving: ${saved} KB"
Per-Process KSM Usage
# Pages merged for a process
cat /proc/<pid>/ksm_merging_pages
# Memory saved for this process (bytes, v6.1+)
cat /proc/<pid>/ksm_stat
Evolution
Introduction (v2.6.32, 2009)
Commit: f8af4da3b4c1 ("ksm: the mm interface to ksm")
Authors: Izik Eidus, Andrea Arcangeli, Chris Wright (Red Hat, VMware)
Note: Pre-2010 LKML archives on lore.kernel.org are sparse. The commit message documents the design.
Originally developed for KVM to reduce memory footprint of virtual machines.
NUMA Awareness (v3.9, 2013)
Commit: 90bd6fd31c80 ("ksm: allow trees per NUMA node") | LKML
Author: Petr Holasek (submitted by Hugh Dickins)
Added merge_across_nodes option to prevent cross-node sharing that hurts NUMA locality.
Per-Process Statistics (v6.1, 2022)
Commit: cb4df4cae4f2 ("ksm: count allocated ksm rmap_items for each process") | LKML
Author: xu xin
Added /proc/<pid>/ksm_stat for per-process memory savings tracking.
Trade-offs
Benefits
| Benefit | Impact |
|---|---|
| Memory savings | Varies widely: ~9% in Meta's diverse workloads, higher for many identical VMs (see Owens et al., IEEE ISPA 2011) |
| Higher VM density | More VMs per host |
| Overcommit | Safely run more than physical RAM |
Costs
| Cost | Impact |
|---|---|
| CPU overhead | ksmd scanning uses CPU cycles |
| COW faults | Write to shared page = page fault + copy |
| Latency | COW adds latency to first write |
| Security | Side-channel attacks possible (timing) |
Security Considerations
KSM can leak information through timing side-channels (CVE-2021-3714):
- Attacker allocates page with guessed content
- If merged quickly, content exists elsewhere
- Timing attack reveals memory contents
- Can be used to bypass ASLR or detect applications running in co-resident VMs
Red Hat recommends disabling KSM in multi-tenant environments (public clouds). The kernel defaults KSM to off (/sys/kernel/mm/ksm/run = 0); applications must explicitly opt in via MADV_MERGEABLE.
Common Issues
High CPU Usage
ksmd consuming too much CPU.
Symptoms: High CPU in ksmd process
Solutions:
- Reduce pages_to_scan
- Increase sleep_millisecs
- Disable if savings are minimal
Low Merge Rate
Few pages being merged.
Debug: Check pages_shared vs pages_unshared
Causes:
- Workloads with unique data
- Scan rate too slow
- Memory not marked MADV_MERGEABLE
NUMA Performance Issues
Cross-node merging hurting performance.
Symptoms: Higher memory latency after KSM enabled
Solution:
KSM vs Other Deduplication
| Method | Scope | Overhead | Use Case |
|---|---|---|---|
| KSM | RAM, runtime | CPU for scanning | VMs, containers |
| zswap | Swap, compressed | CPU for compression | Memory extension |
| Filesystem dedup | Disk | I/O for scanning | Storage efficiency |
| COW filesystems | Disk, snapshots | Metadata overhead | Backups, clones |
References
Key Code
| File | Description |
|---|---|
mm/ksm.c |
KSM implementation |
Kernel Documentation
Mailing List Discussions
- Original KSM patch series - Izik Eidus's July 2009 submission
- KSM NUMA trees and page migration - Hugh Dickins's 2013 NUMA awareness patches
Related
- reclaim - Memory pressure interaction
- numa - Cross-node merging considerations
- thp - KSM doesn't merge huge pages
- cow - COW behavior when KSM-merged pages are written
Further reading
Documentation/admin-guide/mm/ksm.rst— the kernel admin guide coveringksmdconfiguration, sysfs knobs,MADV_MERGEABLE/MADV_UNMERGEABLE, the stable/unstable tree model, and monitoring counters; rendered at docs.kernel.org- mm/ksm.c — the full KSM implementation: the two red-black trees,
ksmdscan loop, page hashing, COW-page replacement, and NUMA-aware tree management - LWN: KSM: kernel samepage merging — 2009 article introducing the original KSM design by Izik Eidus and Andrea Arcangeli, focused on the KVM VM-density use case
- LWN: KSM comes to anonymous memory — coverage of Meta's production KSM deployment and their ~9% memory savings across a diverse server workload
- Commit f8af4da3b4c1 — the v2.6.32 KSM introduction; the commit message describes the stable/unstable tree design and the
MADV_MERGEABLEopt-in interface - Commit 90bd6fd31c80 — v3.9
merge_across_nodes=0support; prevents cross-NUMA-node merging that degrades memory locality - Commit cb4df4cae4f2 — v6.1 per-process KSM statistics via
/proc/<pid>/ksm_stat