<aside> π§
Module 08 Β· Virtual memory, paging and page faults
Every process on your machine believes it owns the whole address space. None of them do. This module explains the illusion, who maintains it, and what it costs β and it is the reason free and top memory numbers confuse almost everyone.
π§ concept β π§© real-world analogy β π§ͺ exercise β β expected result (hidden) β π― interview questions (hidden)
</aside>
<aside> β
Before you start, you should already know:
From Module 01 β the kernel/user split, the syscall boundary, and that /proc/PID/ exposes kernel data about a process.
From Module 02 β fork, and that the child starts as a copy of the parent.
From Module 03 β file descriptors, inodes, and that a file has blocks on disk.
From Module 07 β that the kernel interrupts a running thread whenever it needs to.
</aside>
<aside> π
Official docs: Memory management β concepts overview Β· proc_pid_maps(5)
</aside>
When a program uses a variable, the CPU has to turn that into an address β a number saying where in memory. The obvious design is that this number is the real location in the RAM chips. Early computers worked exactly like that.
Three things go badly wrong with that design.
Nothing is protected. If every program uses real RAM addresses, any program can read or write any other program's memory. One buggy line and your password manager's memory is readable by a game.
Programs cannot be built independently. A program is compiled once and run anywhere. If addresses were real, the compiler would have to know in advance which region of RAM is free on your machine β which it cannot possibly know.
You can never use more memory than you have installed. A program needing 3 GB simply cannot run on a 2 GB machine, even if most of that 3 GB is barely touched.
Linux solves all three the same way. A program never sees a real memory address. It sees a virtual address, and hardware translates it to a real one on every single access. Each process gets its own translation, so the same virtual address in two processes points at two different places in RAM.
<aside> π§
The counter-intuitive part. This translation happens on every memory access β every variable read, every instruction fetch, billions of times a second. If it were done in software it would be hopelessly slow. It is done by a dedicated piece of hardware in the CPU, and most of the design of virtual memory exists to make that hardware's job cheap.
</aside>
<aside> π§©
Real-world analogy β post office boxes
Imagine a company where mail is addressed to a physical shelf in the warehouse: "shelf 4, row 12". Everyone must know the real layout. Anyone can walk to shelf 4 and take someone else's post. If the warehouse is rearranged, every letter ever written becomes wrong.
Now put a post room in between. Each department gets its own numbering β "box 1, box 2, box 3" β and the post room keeps a private table translating your box 2 to a real shelf. Marketing's box 2 and Finance's box 2 are different shelves, and neither department knows or cares which.
Three problems solved at once. Departments cannot reach each other's post because their numbering does not reach outside their own table. Every department can use the same simple numbering starting at 1. And a box can be listed in the table without a shelf being allocated yet β nothing is reserved until something actually arrives.
Where the analogy stops working. A post room clerk is slow and deliberate. The CPU does this translation billions of times a second, which is why it is silicon and not a person with a ledger.
</aside>
π§ͺ Exercise A1.1 β Two processes, the same addresses, different memory
# Start two identical, separate processes
sleep 300 & P1=$!
sleep 300 & P2=$!
# Where does each one think its stack is?
echo "PID $P1:"; grep '\[stack\]' /proc/$P1/maps
echo "PID $P2:"; grep '\[stack\]' /proc/$P2/maps
# And where does each think the sleep program itself is loaded?
echo "PID $P1:"; head -1 /proc/$P1/maps
echo "PID $P2:"; head -1 /proc/$P2/maps
kill $P1 $P2
<aside> π
Now imagine this at 500 hosts. This sharing is why you can run 200 copies of the same container image on one node without needing 200Γ the memory for the binaries and libraries. It is also why naively summing per-process memory across a fleet produces a number far larger than the RAM you own β the same physical pages get counted once per process. Section C2 is about exactly that mistake.
</aside>