2026-01-17 · Engineering

The macOS Memory Tunables Apple Doesn't Tell You About

You have 32GB of RAM. Activity Monitor shows half as "inactive" and "file cache." You launch a third instance of your AI coding assistant and suddenly you're swapping. What gives?

The Problem

Apple's philosophy: "unused RAM is wasted RAM." The kernel caches aggressively, betting you'll need those files again. In theory, cache is "free" — evictable on demand.

In practice, "on demand" has a cost. When you spike memory usage, macOS has to compress pages, evict cache, and sometimes swap — all while you wait.

Finding the Knobs

While investigating why three Claude Code instances caused swap pressure on an M4 Mac Mini with 32GB, I found these kernel parameters:

$ sysctl kern.vm_page_free_target kern.vm_page_free_min
kern.vm_page_free_target: 4000
kern.vm_page_free_min: 3500

macOS uses 16KB pages. Those defaults translate to:

On a 32GB machine, that's 0.2% headroom. The kernel doesn't start proactively reclaiming until you're nearly out.

What They Do

From the XNU kernel source (osfmk/vm/vm_page.h):

vm_page_free_target  /* How many pages do we want free? */
vm_page_free_min     /* When to wakeup pageout */

The pageout daemon sleeps until free pages hit these thresholds. With defaults this low, it's reactive — scrambling when you're already in trouble rather than staying ahead.

The Fix

Increase the thresholds for proactive reclamation:

# 4× default: ~256MB headroom
sudo sysctl kern.vm_page_free_target=16000 kern.vm_page_free_min=12000

# 8× default: ~512MB headroom  
sudo sysctl kern.vm_page_free_target=32000 kern.vm_page_free_min=24000

Verify:

$ sysctl kern.vm_page_free_target kern.vm_page_free_min
kern.vm_page_free_target: 16000
kern.vm_page_free_min: 12000

Results

Tested on macOS 15 Sequoia, M4 Mac Mini (32GB):

Test Result
Writable without SIP changes
Takes effect immediately
Survives sleep/wake
Survives reboot

To persist, create /etc/sysctl.conf:

sudo tee /etc/sysctl.conf << 'SYSCTL'
kern.vm_page_free_target=16000
kern.vm_page_free_min=12000
SYSCTL

Monitoring

Check if it's helping:

# Memory pressure (should stay green more often)
memory_pressure | grep "free percentage"

# Watch compression vs swap ratio
vm_stat | grep -E "(Compressions|Swapouts)"

You want high compressions (fast, in-RAM) and low swapouts (slow, disk I/O). The tuning should shift the ratio toward compression.

Why So Low by Default?

Apple optimizes for the common case: 8-16GB machines, light workloads. Maximum cache means faster app launches. The occasional swap spike is acceptable.

If you're running Docker, simulators, multiple Electron apps, or AI tooling — you're not the common case.

The Nuclear Option

sudo purge

Clears inactive memory immediately. But it's one-shot — cache refills. The sysctl approach maintains ongoing headroom.

Caveats

Related Tunables

Other interesting sysctls (read-only on modern macOS, but worth checking):

sysctl kern.vm_page_speculative_percentage  # speculative cache limit
sysctl kern.vm_page_speculative_q_age_ms    # how long speculative pages live

macOS memory management is good. The defaults just assume you want maximum caching. If you've got RAM to spare and hate swap latency, now you know where the knobs are.

Tested January 2026, macOS 15 Sequoia, Apple M4.

See also: How We Found macOS Memory Tunables by Arguing with an AI — the story of how this was discovered