[savvyadmin] 0:home1:processes2:recipes3:explain4:archive linux & server reference since 2007
david@web-1:~$ man kswapd0

KSWAPD0(7) Savvy Admin Process Reference KSWAPD0(7)

NAME

kswapd0 — Kernel thread that reclaims memory in the background when a zone's free pages fall below the low watermark; one per NUMA node, kswapd0 is node 0.

kind: kernel thread · binary: kernel thread (PPID 2, no executable) · updated 2026-10-20

SAFE TO KILL?

VERDICTNO. It is a kernel thread: kill sends a signal to nothing, and even if you could stop it, allocations would fall into direct reclaim and stall every process instead. kswapd0 eating CPU is the symptom of memory pressure, never its cause. Find what holds the memory, give the box swap or RAM, or move the watermarks so reclaim starts earlier.

SYMPTOMS

· kswapd0 pinned at 50–100% CPU while 'available' memory in free -h is close to zero
· si/so columns in vmstat are non-zero: pages are being swapped in and out (swap thrash)
· high iowait, everything feels sluggish, the real hog is a process with a huge RSS
· /proc/pressure/memory shows 'some' avg10 well above 0 — tasks are stalling on memory

DIAGNOSE

$ free -h is 'available' near zero, and is swap in use at all? No swap plus full RAM means kswapd can only evict page cache, over and over$ vmstat 1 5 si/so = pages swapped in/out per second, wa = iowait. Non-zero si/so while kswapd0 is busy is swap thrash, not a kernel bug$ cat /proc/pressure/memory PSI: 'some' = at least one task stalled on memory, 'full' = all non-idle tasks stalled; avg10/avg60/avg300 are percentages of recent wall time, total is µs. Needs kernel ≥ 4.20 built with CONFIG_PSI — 'No such file' means the kernel lacks it (some cloud and microVM kernels do)$ grep -E '^(pgscan_kswapd|pgsteal_kswapd|pgscan_direct|pgsteal_direct|allocstall_normal|allocstall_movable|kswapd_low_wmark_hit_quickly)' /proc/vmstat background (kswapd) vs direct reclaim counters; run it twice a few seconds apart. Growing allocstall_* means processes are stalling in direct reclaim because kswapd cannot keep up$ ps -eo pid,user,rss,pmem,comm --sort=-rss | head -15 who actually holds the memory (RSS in KiB). This list, not kswapd0, is what you act on$ grep -E '^Node|^ pages free|^ (min|low|high) ' /proc/zoneinfo per-zone watermarks in 4 KiB pages: kswapd wakes when free drops below 'low' and sleeps again above 'high'; below 'min' allocations do direct reclaim$ sysctl vm.swappiness vm.watermark_scale_factor vm.min_free_kbytes the three knobs that decide how early kswapd starts and whether it prefers dropping page cache or swapping anonymous pages$ swapon --show empty output = no swap device. On a small VPS that alone explains a permanently busy kswapd0

FIX

1. Fix the memory hog, not the messenger. A database buffer pool sized for a bigger box, a JVM heap, a leaking worker: shrink it, restart it, or move it. kswapd0 goes quiet by itself when free memory climbs back over the high watermark.

$ ps -eo pid,user,rss,pmem,args --sort=-rss | head -5

2. Give the kernel somewhere to put cold pages: add a swap file. Persist with a line in /etc/fstab: /swapfile none swap sw 0 0. Swap is not a RAM substitute; it lets reclaim evict genuinely idle anonymous memory instead of thrashing the page cache. On a copy-on-write filesystem such as Btrfs the file must be created with chattr +C first; see the distribution's swap page.

$ sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile

3. Wake kswapd earlier so it reclaims in the background instead of stalling allocations. Units are fractions of 10,000 of memory: default 10 (0.1%), maximum 3000. Raise it when allocstall_* counters grow or kswapd_low_wmark_hit_quickly is high. Persist in /etc/sysctl.d/90-reclaim.conf.

$ sudo sysctl vm.watermark_scale_factor=200

4. Tell reclaim what to evict first with swappiness. Default 60, range 0–200. Lower keeps anonymous memory and drops page cache first (databases that manage their own cache); 100 treats both as equal cost; values above 100 are legitimate with zram/zswap, the kernel docs give 133 as an example for swap twice as fast as the filesystem.

$ sudo sysctl vm.swappiness=10

5. Let a userspace OOM daemon end the thrash before the kernel OOM killer does. systemd-oomd (Ubuntu 22.04+ ships it, enabled on Desktop, usually inactive on Server) and earlyoom watch PSI and kill the hog at a threshold you choose, instead of letting kswapd0 spin for ten minutes first.

$ systemctl is-active systemd-oomd

6. On kernels with Multi-Gen LRU, protect the working set. 0x0007 means MGLRU is on, 0x0000 means compiled in but switched off (write y to enable), 'No such file' means the kernel lacks CONFIG_LRU_GEN (kernel ≥ 6.1; WSL2 lacks it, a 6.18 cloud guest shipped it off). min_ttl_ms keeps the last N ms of working set in memory and prefers an OOM kill over thrashing; 1000 is the documented starting point.

$ cat /sys/kernel/mm/lru_gen/enabled

IMPOSTORS

$ ps -o pid,ppid,user,comm -C kswapd0 a real kswapd0 is owned by root with PPID 2 (kthreadd). Any other parent, or a copy under a normal user, is a process that merely calls itself kswapd0 — cryptominers have used exactly this name since 2019$ readlink /proc/$(pgrep -x kswapd0 | head -1)/exe || echo 'no exe: genuine kernel thread' kernel threads have no executable; a path under /tmp, /dev/shm or a home directory is malware wearing the name

DISTRIBUTIONS

ubuntu 22.04+ ships systemd-oomd (active on Desktop, inactive on Server unless enabled); PSI is on by default; MGLRU is enabled on the generic 6.x kernels but not on every cloud or WSL2 kernel — check /sys/kernel/mm/lru_gen/enabled.
any Cloud images often ship with zero swap. A 1–2 GiB swap file plus vm.swappiness=10 is the usual first fix on a small VPS.

APPLIES TO

Linux 2.6 and later. /proc/pressure needs kernel 4.20+ with CONFIG_PSI; Multi-Gen LRU needs 6.1+ with CONFIG_LRU_GEN. Per-cgroup pressure is in memory.pressure on cgroup v2.

SEE ALSO

kcompactd(7) — card not written yet, systemd-oomd(7) — card not written yet, kworker(7) — card not written yet

SOURCES

1. Kernel docs — Concepts overview: reclaim, watermarks, direct reclaim, fetched 2026-10-20
2. Kernel docs — sysctl/vm: swappiness, watermark_scale_factor, min_free_kbytes, fetched 2026-10-20
3. Kernel docs — PSI: pressure stall information, fetched 2026-10-20
4. Kernel docs — Multi-Gen LRU admin guide, fetched 2026-10-20
Machine-readable: /process/kswapd0.json · changelog 2026-10-20: first version. Every command was run on both test kernels; both run the distro in a PID namespace that hides kernel threads, so the ps -C kswapd0 / readlink impostor checks ran against an empty result and still want a pass on a bare-metal or full-VM kernel. The 6.18 guest had no /proc/pressure (built without CONFIG_PSI) and MGLRU compiled in but off (0x0000) — both now noted in the card

Ubuntu 22.04 · kernel 6.6 (WSL2) and Ubuntu 26.04 · kernel 6.18 (Firecracker VM) 2026-10-20 KSWAPD0(7)
Manual page kswapd0(7) (END)