Loading learning content...
Before paging became the dominant memory management paradigm, operating systems faced a stark choice when memory ran low: swap out an entire process. This technique—known as standard swapping or whole-process swapping—was the original meaning of the term "swap."
In standard swapping, when memory pressure occurs, the operating system selects an entire process and writes all of its memory to disk. The freed memory can then be used by other processes. When the swapped-out process needs to run again, the system reads its entire memory image back from disk.
Understanding standard swapping is crucial for several reasons: it illuminates the historical evolution of memory management, explains terminology that persists in modern systems, and reveals why paging-based approaches became dominant. Moreover, some modern systems still employ process-level swapping as a last-resort mechanism under extreme memory pressure.
By the end of this page, you will understand how standard swapping works, its historical context, the role of the swapper (scheduler), the mechanics of process swap out and swap in, and why modern systems prefer page-based swapping while occasionally falling back to process-level mechanisms.
To appreciate standard swapping, we must travel back to the computing era of the 1960s and 1970s, when the constraints were radically different from today.
The time-sharing challenge:
Imagine a university mainframe in 1975. Twenty students are logged in via terminals, each running a text editor or compiler. The total memory demand might be 20 × 200KB = 4MB. But the machine has only 1MB of RAM.
The solution: multiprogramming with swapping. At any moment, only a subset of processes are in memory. When a user pauses (e.g., to read output or think), their process is swapped out, making room for another user's process to swap in. When the first user types a command, their process is swapped back.
This approach worked because:
The math of early swapping:
Since user think time vastly exceeded swap time, the system remained responsive despite frequent swapping.
Early Unix systems on the PDP-11 (Ken Thompson and Dennis Ritchie, 1970s) used standard swapping extensively. The entire address space of a process would be written to a swap area. The term 'swap' in Unix permanently derives from this whole-process swapping model, even though modern implementations swap pages rather than processes.
In standard swapping, the unit of swapping is the entire process memory image. When a process is swapped out, all of its allocated memory is written to disk. When swapped in, the entire image is read back.
The contiguity requirement:
A critical aspect of early standard swapping was the requirement for contiguous memory allocation. When a process is swapped in, it needs a single block of memory large enough to hold its entire image. This requirement had significant implications:
External fragmentation — As processes swap in and out, gaps form between allocated regions. Eventually, total free memory might be sufficient, but no single contiguous block is large enough.
Compaction — To solve fragmentation, the OS might compact memory, sliding all processes to one end. This was expensive (copying gigabytes of data), but necessary.
Fixed partitions — Some systems used fixed memory partitions. Each process was assigned to a partition of appropriate size, simplifying allocation but wasting memory if processes didn't fill their partitions.
These limitations were primary motivators for the development of paging, which we'll compare in a later section.
In systems using standard swapping, a specialized component called the swapper (also known as the medium-term scheduler) makes swapping decisions. This component bridges the gap between short-term scheduling (which process runs next on the CPU) and long-term scheduling (which jobs are admitted to the system).
| Scheduler | Time Scale | Decision | Frequency |
|---|---|---|---|
| Long-term (Job Scheduler) | Minutes to hours | Which jobs are admitted to the system? | Rarely (batch systems) |
| Medium-term (Swapper) | Seconds to minutes | Which processes are in memory vs. swapped? | Periodically |
| Short-term (CPU Scheduler) | Milliseconds | Which ready process runs next? | Constantly |
The swapper's role:
The swapper daemon (often implemented as a kernel thread or privileged process) continuously monitors system memory state and makes swap decisions based on several factors:
Memory availability — When free memory drops below a threshold, the swapper identifies processes to swap out
Process state — Processes that have been waiting (blocked) for a long time are prime candidates for swap-out. Sleeping processes don't need their memory in RAM.
Priority — Lower-priority processes are preferred victims for swap-out. High-priority or real-time processes may be protected.
Residency time — Processes that have been in memory for a long time without running may be swapped out. Conversely, recently swapped-in processes get grace time before being swapped out again.
Memory size — Swapping a large process frees more memory but takes longer. The swapper balances these factors.
Swap-in decisions:
The swapper also decides when to bring swapped-out processes back:
Event occurrence — When a blocked process's event occurs (I/O completes, semaphore signaled), it should be swapped in to resume.
Time quantum — Some systems periodically swap in waiting processes to ensure fairness.
Memory availability — If memory becomes plentiful, swapped processes may be brought in proactively.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
// Conceptual swapper algorithm (medium-term scheduler) procedure SWAPPER: loop forever: sleep(SWAPPER_INTERVAL) // e.g., 1 second // SWAP-OUT PHASE: Free memory if needed while free_memory < LOW_THRESHOLD: victim = select_swap_out_candidate() if victim == NULL: break // No suitable candidates swap_out(victim) add_to_free_list(victim.frames) victim.state = SWAPPED_OUT // SWAP-IN PHASE: Bring back waiting processes for each process P in swapped_out_queue: if should_swap_in(P): if free_memory >= P.memory_size: swap_in(P) P.state = READY add_to_ready_queue(P) else: break // Not enough memory function select_swap_out_candidate(): // Selection criteria: // 1. Prefer blocked processes over ready/running // 2. Prefer lower priority // 3. Prefer longer time since last active // 4. Prefer smaller processes (faster swap) best_candidate = NULL best_score = -INFINITY for each process P in memory: if P.is_locked or P.is_kernel: continue score = compute_swap_score(P) if score > best_score: best_score = score best_candidate = P return best_candidate function should_swap_in(P): // Swap in if: // 1. P is now runnable (event occurred) // 2. P has been swapped out too long (fairness) // 3. P has high priority and we have memory return P.is_runnable and (time_since_swap_out(P) > MAX_SWAP_TIME or P.priority > PRIORITY_THRESHOLD)If the swapper is too aggressive, it can cause thrashing: processes are swapped out shortly before their events occur and swapped back in, only to be swapped out again. This wastes enormous I/O bandwidth. The swapper must use hysteresis—processes that were recently swapped in should be protected from immediate swap-out.
In standard swapping, when a process is swapped out, its entire memory image must be written to swap space. The operating system must therefore manage swap space allocation at the process level, reserving and tracking regions large enough to hold complete process images.
Contiguous vs. scattered swap allocation:
Early standard swapping often allocated contiguous regions in swap space for each process, mirroring the contiguous memory allocation requirement. This simplified I/O (one large sequential read/write) but caused the same fragmentation problems as memory allocation.
Later systems allowed scattered swap allocation:
This reduced fragmentation but increased management complexity and sometimes I/O overhead.
Modern relevance:
Although page-based swapping has largely replaced process-level swap allocation, the concept survives in:
Linux OOM handling — Under extreme pressure, Linux's OOM killer terminates processes entirely, effectively "swapping out" their memory (though not to disk in recoverable form)
Container memory limits — Container runtimes may "freeze" a container (saving state to disk) when memory limits are exceeded
Hibernation — The entire system state (all processes) is written to swap, resembling mass standard swapping
| Strategy | Advantages | Disadvantages |
|---|---|---|
| Pre-allocation | Swap-out never fails; simple accounting | Wastes swap space; limits process count |
| On-demand allocation | Efficient space usage | Swap-out may fail; OOM risk |
| Contiguous regions | Fast sequential I/O | Swap fragmentation; allocation challenges |
| Scattered allocation | No fragmentation issues | Complex management; potential seek overhead |
While standard swapping solved the fundamental problem of limited memory, it had significant limitations that became increasingly problematic as systems evolved.
The scaling problem:
Consider a modern workstation with:
With standard swapping:
This is clearly unacceptable for modern interactive systems. The solution—demand paging—allows portions of processes to reside in memory while the rest remains on disk, swapping individual pages rather than entire process images.
The working set insight:
The key realization driving paged memory was the working set concept: at any moment, a process actively uses only a small subset of its pages. If we keep the working set in memory and swap only cold pages, we can support many large processes simultaneously.
A 4GB process might have a 100MB working set. Five such processes need only 500MB of RAM (for their working sets), not 20GB (for complete images). The remaining pages can stay on disk until needed.
Standard swapping doesn't exploit locality of reference. Programs don't access their entire address space uniformly—they spend 90% of time in 10% of code. Paging exploits this by keeping hot pages in RAM while cold pages can remain on disk indefinitely.
Despite its limitations, elements of standard swapping persist in modern operating systems, typically as emergency mechanisms when page-level swapping proves insufficient.
Linux swappiness and per-process behavior:
Linux's /proc/sys/vm/swappiness parameter (0-200, default 60) influences how aggressively the kernel swaps. At low values, the kernel strongly prefers evicting file-backed pages; at high values, it more readily swaps anonymous pages.
For individual processes, Linux supports:
# View a process's memory status
cat /proc/<pid>/status | grep -E "VmSwap|VmRSS"
# VmRSS: 12345 kB (resident in RAM)
# VmSwap: 6789 kB (in swap)
# Lock process memory (prevent swapping)
mlock() system call or mlockall(MCL_CURRENT | MCL_FUTURE)
When complete swap-out makes sense:
In certain scenarios, swapping entire processes remains logical:
Modern mobile OSes often kill background processes rather than swap them, prioritizing startup speed over preservation. Relaunching an app takes seconds; swapping it back in might take longer and still require initialization. This is a pragmatic trade-off enabled by fast flash storage and app architectures designed for quick restart.
The transition from standard swapping to demand paging was one of the most significant advances in operating system design. Let's compare these approaches systematically.
| Aspect | Standard Swapping | Demand Paging |
|---|---|---|
| Unit of swap | Entire process | Individual page (e.g., 4KB) |
| Memory residency | All-or-nothing | Partial (working set in RAM, rest on disk) |
| Swap granularity | Process size (MB-GB) | Page size (KB) |
| I/O efficiency | Large sequential transfers | Many small transfers (with read-ahead) |
| Fragmentation | External (in memory and swap) | Internal only (last page of allocation) |
| Sharing support | Limited or none | Shared pages map to same frames |
| Start-up cost | Full swap-in before execution | Pages loaded on first access |
| Locality exploitation | None | Working set pages stay in RAM |
| Memory utilization | Poor (cold pages in RAM) | Excellent (only hot pages in RAM) |
| Implementation complexity | Relatively simple | Complex (page tables, TLB, fault handlers) |
Why demand paging won:
The advantages of demand paging are overwhelming for general-purpose systems:
Better multiprogramming — With demand paging, 50 processes with 1GB address spaces but 50MB working sets need only ~2.5GB RAM, not 50GB. Memory utilization improves dramatically.
Faster startup — A process can begin executing immediately; code pages load on first access. No waiting for full swap-in.
Efficient sharing — Libraries like libc are loaded once and shared across all processes via page table mappings. Standard swapping would replicate them.
Graceful degradation — As memory pressure increases, only cold pages are evicted. The system slows but doesn't stop. With standard swapping, processes alternate between full-speed and completely stalled.
Fine-grained policies — Page replacement algorithms can make nuanced decisions: which specific pages to evict, based on access patterns. Standard swapping has only coarse process-level choices.
Trade-offs:
Demand paging isn't universally superior:
For soft real-time or latency-sensitive workloads, these trade-offs may favor memory locking over either swapping approach.
Standard swapping was the original solution to the memory scarcity problem, enabling time-sharing and multiprogramming when RAM was prohibitively expensive. While demand paging has largely superseded it, understanding standard swapping illuminates operating system evolution and remains relevant for specialized scenarios.
What's next:
We've seen standard (process-level) swapping and understand its limitations. The next page explores swapping with paging—how modern systems combine these concepts, using page-level granularity while still supporting process suspension and hibernation when necessary.
You now understand standard swapping: its historical role, mechanics, limitations, and modern appearances. Next, we'll see how paging transforms swapping into a fine-grained, efficient memory management technique.