Handbooks  /  Operating Systems Fundamentals
Handbook~16 min readSystemsworked math + runnable code
The Operating Systems Fundamentals Handbook

Sharing what
isn't enough.

Your laptop runs hundreds of programs on a handful of CPU cores and a fixed slab of RAM. None of them has enough — and yet they all run, smoothly, as if each owned the machine. That illusion is the operating system's whole job: take one scarce resource and share it so cleverly that everyone thinks they have it to themselves. Two tricks carry most of the weight — slicing time so no program starves the CPU, and paging memory so the working set fits even when the whole doesn't. This handbook is those two tricks, worked out.

01

The illusion machine

An operating system is two things at once: a resource manager that shares scarce hardware — CPU, memory, disk, devices — among competing programs, and an abstraction layer that hides the messy hardware behind clean ideas: a process (a running program with its own memory), a file, a socket. Every program you run believes it has the whole machine. The OS maintains that fiction.

The fiction rests on two central scarcities. There's one CPU (or a few cores) but many programs want to run — so the OS schedules, deciding who runs now and for how long. And there's limited RAM but programs collectively want more — so the OS uses virtual memory, giving each process a private address space larger than physical memory by keeping only hot pages in RAM. Master these two — time-sharing the CPU and space-sharing memory — and you understand the beating heart of every OS. Everything else (filesystems, drivers, system calls) is built on top.

The one-sentence version

An OS shares one CPU by slicing time (round-robin, so nothing starves) and shares limited RAM by paging (LRU, so the hot pages stay and the cold ones spill to disk) — two ways to make a scarce resource feel like enough.

02

Slicing the CPU

A CPU core can run exactly one instruction stream at a time, yet your machine runs hundreds of processes "simultaneously." The trick is speed: the OS runs a process for a tiny slice, then switches to another, fast enough that all of them appear to progress at once. The simplest fair policy is round-robin: give each ready process a fixed slice — a quantum — then rotate to the next, sending the interrupted one to the back of the queue.

Every rotation costs a context switch: the OS saves the running process's registers and state, and loads the next process's — pure overhead, no useful work done during it. That sets up the central tension of scheduling. A large quantum means fewer switches (less overhead) but worse responsiveness — a short interactive task waits behind long ones, degrading toward first-come-first-served. A small quantum means snappy responsiveness but more time lost to switching. Real schedulers (Linux's CFS, priority multilevel queues) are far more sophisticated, but they're all refinements of the same idea round-robin makes plain: rotate the CPU so no one starves, and pay for fairness in context-switch overhead.

03

Paging memory

Virtual memory gives every process a large, private, contiguous address space — an illusion, because physical RAM is small and shared. Memory is cut into fixed-size pages; the OS maps each virtual page to a physical frame, keeping only the actively used pages in RAM and leaving the rest on disk. When a process touches a page that isn't resident, the hardware raises a page fault, and the OS fetches it from disk — evicting another page if RAM is full.

A page reference under LRU (3 frames)
HitPage already in a frame → fast (nanoseconds); mark it recently used.
FaultPage not resident → page fault: load from disk (millions of times slower).
Evict (LRU)RAM full? Drop the least-recently-used page — betting hot pages stay hot.
More framesMore RAM → fewer faults (usually) → the working set fits.

Because a disk fetch is millions of times slower than a RAM hit, the whole game is minimizing page faults, and that's what the replacement policy decides. LRU — evict the least-recently-used page — bets on locality: a page used recently is likely to be used again soon, so the coldest page is the safest to drop. Most real programs have strong temporal locality, so LRU keeps fault rates low. Its exact form is costly to track, so kernels approximate it (clock/second-chance), but the principle is the same one behind every cache: keep what's hot, evict what's cold.

04

The scheduling & paging math

Round-robin serves each process a quantum in rotation; a process finishes when its accumulated slices cover its burst, so short jobs leave the rotation first. Paging counts a fault whenever a referenced page isn't resident:

round-robin:  run(p) = min(quantum, remaining(p))  each turn,  requeue while remaining > 0  ⟹  fair rotation, no starvation

Bursts A=4,B=2,C=1 with quantum 2 finish in order B, C, A — B and C complete in round one, A drags to the end.

Page faults fall (weakly) as frames rise, because more RAM holds a larger working set — and the hit ratio is one minus the fault fraction:

faults(refs, frames)  counts misses under LRU     hit ratio  =  1 − faults / |refs|     frames↑ ⟹ faults↓

The reference stream 1,2,3,4,1,2,5,1,2,3,4,5 causes 10 faults with 3 frames but only 8 with 4 — more RAM, fewer trips to disk. The runnable version below simulates both.

RUN IT YOURSELF

Scheduling and paging, simulated

Two OS jobs, both about sharing a scarce resource. Round-robin scheduling gives each ready process a fixed quantum in rotation and requeues anything unfinished, so nothing starves and short jobs finish first. Virtual memory keeps hot pages in a small set of frames and evicts the least-recently-used one on a fault — so more frames means fewer faults, and the hit ratio is one minus the fault fraction. Change the burst times, the quantum, the reference stream, or the frame count and watch the finish order and the fault counts move.

CPython · WebAssembly
05

The vocabulary

A handful of terms unlock most OS discussions:

TermWhat it is
ProcessA running program with its own private memory and resources. Isolated from other processes by the OS.
ThreadA unit of execution within a process. Threads share the process's memory — cheap to switch, but need synchronization.
Context switchSaving one process/thread's state and loading another's. The overhead of sharing the CPU.
System callA process's request for the OS to do something privileged (read a file, open a socket). The user/kernel boundary.
Page faultA reference to a page not in RAM, trapping into the OS to load it from disk.
Kernel vs user modePrivileged CPU mode (full hardware access) vs restricted mode (apps run here). The wall that keeps a crashing app from taking down the machine.

The through-line is isolation and mediation: processes can't touch each other's memory or the hardware directly — they ask the kernel, which arbitrates. That's why a buggy app crashes alone instead of taking the system with it, and why the CPU has a hardware-enforced kernel/user boundary at all. Scheduling and paging are how the kernel shares the CPU and memory; the rest of the vocabulary names the machinery that keeps the sharing safe.

06

Pitfalls

The first practical trap is thrashing: when the working set of active pages is larger than physical RAM, the system spends nearly all its time paging in and out instead of computing — every reference faults, evicts a page that's about to be needed, and faults again. Performance falls off a cliff. The fix is more RAM or fewer concurrent processes; the lesson is that virtual memory's magic ends the moment your hot data doesn't fit, and it ends catastrophically, not gracefully.

Two more that trip up application engineers. Ignoring context-switch cost: spawning thousands of threads doesn't multiply throughput on a few cores — past the core count you just add switching overhead, which is why async I/O and thread pools exist (don't out-thread your CPUs). And assuming memory access is uniform: it isn't — an L1 cache hit is nanoseconds, a RAM hit tens of nanoseconds, a page fault to disk milliseconds, a spread of a million to one. Data-structure and access-pattern choices that respect locality (arrays over linked lists, sequential over random) can dwarf algorithmic constants, because they turn faults into hits. You don't write a scheduler or a pager, but you live inside theirs: understand time-slicing and paging and you'll know why your program is fast, slow, or thrashing. The whole handbook is one line: the OS shares scarce time and space, and your performance is decided by how well your work fits the slices and the frames.

Worth knowing

Keep the working set inside RAM or you thrash; don't spawn more busy threads than cores or context switches eat the gains; and respect the memory hierarchy — locality turns million-to-one page faults into nanosecond hits. You live inside the OS's scheduler and pager even when you never call them directly.

Frequently asked

Quick answers

What does an OS do?

Shares scarce hardware (CPU, RAM, disk) among programs and hides it behind clean abstractions — processes, files, sockets. Core jobs: scheduling and memory management.

What is round-robin scheduling?

Each ready process gets a fixed quantum in rotation, then a context switch to the next — so nothing starves. Quantum size trades responsiveness against switch overhead.

What is paging?

Memory split into pages mapped to physical frames; only hot pages stay in RAM. A reference to a non-resident page faults and loads it from disk.

What is LRU replacement?

On a full RAM, evict the least-recently-used page — betting on locality that recent pages will be reused. Minimizes faults for typical workloads.

Finished this one? 0 / 99 Handbooks done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.