Lesson 21 / 22
Swap Space
Pressure lasts 84 seconds, but the used-swap indicator raises a false alarm for 272 seconds, free memory for 451; as the swap area grows, the closability diagnosis rises from 44 wrong to 354 wrong.
Contents
The previous lessons treated storage only as a layer that holds data: partitions, file systems, mount points, and logical volumes. A portion of the same block device, though, holds no files at all and appears at no mount point. That portion is where pages are written when memory falls short.
This lesson’s question is not one of storage but of seeing: in which indicator does swap usage show up, and how late. The answer will not come out one-directional. Some indicators report pressure late, one keeps reporting it even after the pressure has passed, and one shouts even when there is no pressure at all.
Swap Space and What It Is Not
Swap is the disk space pages that do not fit in physical memory get written to. It can be a partition, it can be a file; both are formatted the same way and activated the same way. The file form is flexible because it can be added and removed afterward, the partition form is plain because it is independent of the file system’s state. The difference between them is not a ranking of superiority but a management preference.
The mechanics of paged memory were measured in the Operating System Concepts course: translating a virtual page to a physical page, the page fault, and the page-replacement procedure are defined there and are not repeated here. This lesson counts only what the operator can see.
What can be seen is a handful of numbers: swap’s total size, its used
portion, pages written to swap and read from swap per second, free memory,
and available memory. These are read through swapon --show, free, and
the file holding memory statistics. The transcript below is a sample
transcript showing the shape of the output; it was not run, and no
numeric claim in this lesson comes from it.
NAME TYPE SIZE USED PRIO
/dev/sdb4 partition 4G 1.2G -2
total used free shared buff/cache available
Mem: 7.6G 4.1G 160M 88M 3.3G 3.1G
Swap: 4.0G 1.2G 2.8G
The free and available columns being separate in the transcript is the
subject of this lesson’s first measurement: one does not count reclaimable
cache as free, the other does.
Four Indicators, Four Separate Errors
The measurement is done in a 600-second window on the fictional server. The report-producing unit starts growing gradually from the two-hundredth second, finishes its work at the three-hundred-twentieth second; there is one more short, sharp spike at the four-hundred-eightieth second.
- ST32 — Physical memory is 1200 pages, the usual resident demand is 900 pages. Pressure is the second demand exceeds physical memory, and the oracle knows this.
- ST33 — A page written to swap stays there; used swap does not decrease until it is read back. This is the behavior that is the axis of the measurement.
- ST34 — The cache fills free memory and grows by four pages per second. Available memory counts reclaimable cache as free.
- ST35 — The warning threshold is 100 pages. The tool looks once
every
intervalseconds; between two looks, the operator’s belief is the last reading.
"""How late (or how early) swap usage shows up in each indicator.""" SEED = 20260218 PERIOD = 600 PHYSICAL = 1200 # physical memory, pages BASELINE = 900 # usual resident demand THRESHOLD = 100 # memory warning threshold, pages AMPLITUDE = 60 # fluctuation in demand def generator(seed): d = seed def next_value(n): nonlocal d d = (d * 1103515245 + 12345) % 2147483648 return d % n return next_value def demand(seed=SEED): """Oracle: the resident pages really requested every second.""" r = generator(seed) values = [] for t in range(PERIOD): if 200 <= t < 320: base = BASELINE + (t - 200) * 6 # report job grows gradually elif 480 <= t < 495: base = 1700 # short, sharp spike else: base = BASELINE values.append(base + r(2 * AMPLITUDE + 1) - AMPLITUDE) return values def curves(seed=SEED): d_list = demand(seed) used, rate, free, available, pressure = [], [], [], [], [] peak = previous = 0 for t, d in enumerate(d_list): overflow = max(0, d - PHYSICAL) delta = abs(overflow - previous) # pages sent to and read from swap per second previous = overflow peak = max(peak, overflow) # written page stays until read back headroom = PHYSICAL - min(d, PHYSICAL) cache = min(4 * t, headroom) # cache fills the free space used.append(peak) rate.append(delta) free.append(headroom - cache) available.append(headroom) # reclaimable cache is not counted pressure.append(d > PHYSICAL) return {"used": used, "rate": rate, "free": free, "available": available, "pressure": pressure} RULE = {"used swap": lambda e, i: e["used"][i] > 0, "swap rate": lambda e, i: e["rate"][i] > 0, "free memory": lambda e, i: e["free"][i] < THRESHOLD, "available memory": lambda e, i: e["available"][i] < THRESHOLD} def count(e, rule, interval): missed = false_alarm = 0 last = False for t in range(PERIOD): if t % interval == 0: last = rule(e, t) missed += e["pressure"][t] and not last false_alarm += last and not e["pressure"][t] return missed, false_alarm E = curves() print("oracle: seconds under pressure:", sum(E["pressure"]), "/", PERIOD) print("indicator t=100 t=240 t=300 t=330 t=485 t=560") for name in ("used", "rate", "free", "available"): print(f" {name:14s}", " ".join(f"{E[name][t]:5d}" for t in (100, 240, 300, 330, 485, 560))) print() print("indicator interval missed false alarm wrong diagnosis") for name, rule in RULE.items(): for interval in (5, 30, 60, 120): missed, false_alarm = count(E, rule, interval) print(f" {name:21s} {interval:6d} {missed:9d} {false_alarm:12d}" f" {missed + false_alarm:11d}") print() for seed in (SEED, 20260219): e = curves(seed) s = " | ".join(f"{name.split()[0]} {sum(count(e, k, 5))}" for name, k in RULE.items()) print(f"seed {seed}: pressure {sum(e['pressure']):3d} seconds | interval 5 : {s}")
oracle: seconds under pressure: 84 / 600 indicator t=100 t=240 t=300 t=330 t=485 t=560 used 0 0 331 423 533 535 rate 0 0 57 0 61 0 free 0 0 0 0 0 0 available 268 120 0 258 0 333 indicator interval missed false alarm wrong diagnosis used swap 5 1 272 273 used swap 30 19 265 284 used swap 60 49 265 314 used swap 120 69 225 294 swap rate 5 2 13 15 swap rate 30 19 25 44 swap rate 60 49 85 134 swap rate 120 69 105 174 free memory 5 0 451 451 free memory 30 0 426 426 free memory 60 0 396 396 free memory 120 0 396 396 available memory 5 1 12 13 available memory 30 19 25 44 available memory 60 49 85 134 available memory 120 69 105 174 seed 20260218: pressure 84 seconds | interval 5 : used 273 | swap 15 | free 451 | available 13 seed 20260219: pressure 86 seconds | interval 5 : used 271 | swap 16 | free 469 | available 9
Three numbers side by side. The oracle: the window has 84 seconds of real memory pressure. The tool’s output: the indicator whose name directly names swap, used swap, sits at 423 at the three-hundred-thirtieth second, at 533 after the four-hundred-eighty-fifth, and never comes down. Wrong diagnosis: even read once every five seconds, that indicator raises a false alarm for 272 seconds; its total is 273.
The four indicators have four separate ways of erring. Used swap is cumulative: once a page is written to swap, it stays there until read back, so the indicator stays high even after the pressure ends and shows the past as if it were today; its false alarm reaches 272 seconds. Swap rate is instantaneous, and at a five-second interval it misses only 2 seconds and raises 13 false alarms; when the interval rises to sixty, the missed count jumps to 49, because the spike lasts fifteen seconds and falls between two looks. Free memory alarms almost the whole time — 451 seconds — because the cache fills the free space, and free memory sits near zero even on a healthy system. Available memory misses 1 second and raises 12 false alarms at the five-second interval.
The two lowest totals are 13 and 15, and both depend on the same sampling interval: when the interval rises to sixty, all four climb past 134. In the second seed, pressure lasts 86 seconds, and the five-second-interval totals come out to 271, 16, 469, and 9; the ordering does not change. The course’s rule finds its exact match here: what distinguishes is not how many numbers are looked at, but which number is looked at. The indicator with “swap” in its name turned out to be the worst one for finding swap pressure.
The Cost of Turning It Off
Turning off swap is a one-line command, and it has a one-line risk: every page in the area has to be read back into physical memory. If there is not enough room, the operation either fails or ends with a process being terminated for lack of memory.
- ST36 — Turning off is possible when used swap fits into available memory. The oracle makes this comparison every second.
- ST37 — The diagnosis tested is the common one: if usage percentage is under half, it can be turned off.
"""To turn off swap, every page in it must be read back into memory.""" SEED = 20260218 PERIOD = 600 PHYSICAL = 1200 BASELINE = 900 AMPLITUDE = 60 def generator(seed): d = seed def next_value(n): nonlocal d d = (d * 1103515245 + 12345) % 2147483648 return d % n return next_value def demand(seed=SEED): r = generator(seed) values = [] for t in range(PERIOD): if 200 <= t < 320: base = BASELINE + (t - 200) * 6 elif 480 <= t < 495: base = 1700 else: base = BASELINE values.append(base + r(2 * AMPLITUDE + 1) - AMPLITUDE) return values def state(seed=SEED): used, available, peak = [], [], 0 for d in demand(seed): peak = max(peak, max(0, d - PHYSICAL)) used.append(peak) available.append(PHYSICAL - min(d, PHYSICAL)) return used, available def tally(size, seed=SEED): used, available = state(seed) actual = diagnosed = wrong = 0 for t in range(PERIOD): g = used[t] <= available[t] # oracle: do the pages fit back in memory y = used[t] / size < 0.50 # diagnosis: usage under half actual += g diagnosed += y wrong += g != y return actual, diagnosed, wrong print("swap size closable seconds closable per DIAGNOSIS wrong diagnosis") for size in (512, 1024, 2048, 4096): g, t, y = tally(size) print(f"{size:9d} {g:16d} {t:21d} {y:11d}") print("observation window:", PERIOD, "seconds") print() for seed in (SEED, 20260219): print(f"seed {seed}: " + " | ".join( f"size {size}: wrong {tally(size, seed)[2]}" for size in (512, 4096)))
swap size closable seconds closable per DIAGNOSIS wrong diagnosis
512 246 290 44
1024 246 483 237
2048 246 600 354
4096 246 600 354
observation window: 600 seconds
seed 20260218: size 512: wrong 44 | size 4096: wrong 354
seed 20260219: size 512: wrong 45 | size 4096: wrong 355
Three numbers side by side. The oracle: swap can be safely turned off in 246 of six hundred seconds. The tool’s output: in a 2048-page swap area, usage never rises above fifty percent, meaning the indicator says “fine” in 600 of the window’s 600 seconds. Wrong diagnosis: the same rule is mistaken 44 times at 512 pages, and 354 times at 2048 and above. In the second seed, these two numbers come out to 45 and 355.
The result runs against intuition, and precisely for that reason it is instructive: growing the swap area makes the percentage-based diagnosis worse. The same 533 pages appear as nearly all of a small area, an eighth of a large one; the percentage changes even though the page count does not. A percentage is a ratio, and the ratio’s denominator here is a number the operator chose. The right question is not “how full is swap” but “do the pages inside it fit back into memory,” and the number that answers that question is not in swap’s output but in memory’s.
How Much It Should Be and What Not to Touch
Swap’s size is not a correctness decision but a budget decision, and it has a cost at both ends. On a system with no swap at all, a process gets terminated the moment demand exceeds physical memory; the failure is hard, fast, and easy to diagnose. On a system with generous swap, the same demand produces no termination, but pages go to disk and every read-back adds a wait; the failure is soft, slow, and hard to diagnose. The choice between the two is made according to which failure is manageable.
There is also swap tendency: the system carries a setting that determines how willing it is to write rarely used pages to swap even without memory pressure. Raising this setting pushes the used-swap indicator above zero even when there is no pressure, and grows the false-alarm column in the table above even further.
The destructive-command boundary applies in two places here. First, the command that formats a partition as swap irreversibly destroys the file system on that partition; if the wrong partition name is written, it runs without a warning. Second, turning off swap while under pressure can lead to process termination. This lesson does not give either command in a runnable, complete form. The safe way to test is verifying the target partition’s identity beforehand, doing the trial with swap built on a file, and attempting the turn-off only at a moment when used swap is below available memory.
Summary
- Swap can be a partition or a file, and it appears at no mount point; the mechanics of paged memory are not repeated in this course, what is measured is what the operator can see.
- Real memory pressure in the six-hundred-second window is 84 seconds; even read once every five seconds, the used-swap indicator raises a false alarm for 272 seconds, because a page written to swap stays there until it is read back.
- Free memory raises a false alarm for 451 seconds, because the cache fills the free space; available memory gives the lowest total at the five-second interval, with 1 miss and 12 false alarms.
- Swap rate misses 2 seconds and raises 13 false alarms at the same interval, but when the interval rises to sixty, the missed count jumps to 49; at coarse sampling, all four indicators climb past 134.
- Swap can be safely turned off in 246 of the window’s 600 seconds; the rule that looks at usage percentage is mistaken 44 times at 512 pages, 354 times at 2048 and above — growing the area makes the percentage-based diagnosis worse.
Next Step
Throughout this topic, storage was always something that already existed: a device, partitions on it, file systems inside them. The course’s last lesson returns to the start of the chain and follows a new device joining the system from start to finish — recognition, partitioning, formatting, mounting, making it persistent, and extending it. At every step a tool says “done,” and a layer above is not yet aware of it; what will be measured is how many steps of the chain give a wrong “the work is done” diagnosis. The lesson also closes the course.
To keep your progress and take notes, Log in
My notes
Log in to take notes.