A Mac showing 4 GB of swap allocated may be running perfectly. A Mac showing 4 GB of swap allocated and sustained swap traffic is stalling right now. The number people quote is the first one. The number that predicts the pause is the second.
These are different measurements with different sources, and conflating them is the most common way to misread a machine under load.
Two different counters
Swap used is a level. It comes from vm.swapusage and reports how much swap space is currently allocated.
sysctl vm.swapusage
# vm.swapusage: total = 0.00M used = 0.00M free = 0.00M (encrypted)Swap I/O is a rate. It is derived from the Mach counters swapins and swapouts, declared alongside the rest of the page statistics in XNU's osfmk/mach/vm_statistics.h. They are cumulative page counts, not byte totals. To get a throughput you have to difference them over time yourself:
let inputPages = swapInPages >= previousSwapInPages
? swapInPages - previousSwapInPages
: 0
let input = Double(inputPages) * Double(pageBytes) / durationThree details in that derivation matter more than they look.
The counters are in pages, so the page size has to be applied. On Apple Silicon that is 16384 bytes, not the 4096 many tools assume, and getting it wrong understates swap throughput by a factor of four. Do not take that on trust, because it is one command:
sysctl hw.pagesize
# hw.pagesize: 16384The first reading is always zero. There is no previous counter to subtract from, so the first sample establishes a baseline and reports nothing. Any tool that shows you a swap rate immediately on launch is either showing you a cumulative total mislabelled as a rate, or it waited.
Counter rollback is treated as zero rather than as a negative rate. If the counter goes backwards, the honest output for that interval is no data, not a nonsense number.
Why allocation lags reality in both directions
Swap allocation is sticky. macOS does not eagerly reclaim swap space once the pressure that created it has passed. A machine that spent ten minutes under heavy memory pressure this morning can still report gigabytes of swap allocated this afternoon while running comfortably, with no swap traffic at all.
The reverse also happens, and it is the more dangerous case. Swap allocation starts at zero and climbs. A machine that is one minute into a serious memory shortfall can be actively paging while the allocated total is still small. The stall is already happening. The number people watch has barely moved.
This is why swap used is a poor trigger for any decision. It describes history with an unpredictable lag in both directions.
What a stall actually looks like
When a working set genuinely exceeds physical memory, macOS runs a sequence of increasingly expensive responses. It reclaims cached pages first. It compresses. Only when compression is no longer keeping up does it write pages to disk, and only then does swap-out throughput become non-zero. Apple counts both stages in the same picture: the Activity Monitor memory pressure graph is determined by free memory, swap rate, wired memory, and file cached memory together.
The order matters for diagnosis. Sustained non-zero swap I/O means the cheaper mechanisms have already been exhausted. It is not an early warning. It is a confirmation that you are past the point where the machine can absorb the workload quietly.
Swap-in traffic is the half that produces the pause you feel. A page that was written out has to be read back before the thread that wants it can continue. During local inference, where the same weights are touched repeatedly, this turns into a loop: pages are evicted, immediately needed again, and read back.
Measured on a machine pushed past its memory
An 8 GiB test allocation never made this Mac swap, because compression and cache reclaim absorbed all of it. Two local models loaded at once did.
Measured on a MacBook Pro, Apple M5 Pro, 48 GB, macOS 27.0 build 26A5425a, Searoom 0.3.0, holding roughly 30 GB of model weights resident at the same time. Full method and model names are in the second-model article.
| State | Free | Compressor | Swap out | Swap in | Swap allocated |
|---|---|---|---|---|---|
| Idle | 10.29 GB | 0.82 GB | 0 | 0 | 0 |
| Under load | 0.05 GB | 17.17 GB | 16 pages | 0 | 0 |
| Shortfall | 0.56 GB | 4.47 GB | 13,756 pages | 0 | 0.23 GB |
| Load removed | 17.80 GB | 2.98 GB | 13,756 pages | 8 | 0.23 GB |
The order in the middle two rows is the argument this article makes. Free memory goes first, the compressor takes 17.17 GB at its peak, and only then does the counter for pages written to disk move at all. By the time swap-out is non-zero, both cheaper mechanisms have already been spent.
The last row is the sticky allocation described above, caught in the act. Long after the models were unloaded and the machine was idle with 17.80 GB free, vm.swapusage still reported 0.23 GB allocated and the cumulative counters had not moved. That is the second row of the table below: residue from earlier pressure, not a current problem. A tool reporting only swap used would have called this machine constrained while it sat doing nothing.
One result was not what the mechanism alone would predict. swapins stayed at zero for the entire shortfall, and reached 8 pages only after the load was removed. Pages were written out and never read back, so no thread ever blocked waiting for one, and the machine stayed responsive throughout. Swap-out on its own was not a stall. That is the sharper version of this article's claim: swap throughput predicts a stall, and it is specifically the swap-in half that produces the pause.
Limits of this measurement
One machine, one macOS build, one workload. 225 MB written out is a modest shortfall and it did not produce a stall a user would notice. A machine driven further past its limit, especially one with less memory to begin with, would show sustained traffic in both directions rather than one-way eviction. What is demonstrated here is the ordering and the stickiness, not the severity.
Reading the three signals together
No single memory metric establishes a cause. The useful diagnosis comes from reading three at once.
| Available memory | Swap used | Swap I/O | Reading |
|---|---|---|---|
| Comfortable | Zero | Zero | Headroom. More workload will fit. |
| Comfortable | Non-zero | Zero | Residue from earlier pressure. Not a current problem. |
| Low | Zero or low | Zero | Absorbed by compression and reclaim. Working, with little margin left. |
| Low | Any | Sustained non-zero | Actively paging. This is the stall. |
The third row is the one worth internalising. A Mac can sit at very low available memory, with free pages near zero, and still be entirely healthy because the compressor is doing its job. Low available memory alone is not a fault condition. Low available memory plus sustained swap traffic is.
Checking it on your own machine
The raw counters are available without installing anything:
sysctl vm.swapusage
vm_stat | grep -E "Swapins|Swapouts"Run the second command twice, a few seconds apart, and subtract. That difference, multiplied by 16384 and divided by the elapsed seconds, is your swap throughput in bytes per second. That is the same arithmetic Searoom performs once per sampling interval.
For a single structured sample including both the level and the rate:
Searoom --dump-sampleThe fields are swapUsed for the allocation, and swapInPerSecond and swapOutPerSecond for the throughput. Definitions for all three are in the metric reference, and the broader question of what pressure means is covered in what macOS memory pressure actually measures.