Frontend Labs
⋯

Part 3 — Memory management

Part 2 gave every process the illusion of its own CPU; this part gives it the illusion of its own memory. Virtual memory and paging are how that illusion is built, and this part also covers what happens once the illusion runs out — swapping, and the OOM killer deciding who dies.

Chapter 10 — Virtual memory: every process's private lie

In one sentence

Every process gets its own private, seemingly-huge range of memory addresses that has almost nothing to do with the actual physical RAM chips — the kernel and the CPU together translate one into the other, invisibly, on every single memory access.

Why this matters

This is why one process can't (accidentally or maliciously) read another process's memory, why your program can use memory addresses that don't "physically" exist yet, and why "how much RAM does this process really use" turns out to be a surprisingly subtle question (Chapter 31's RSS vs VSZ).

How it actually works

   WITHOUT VIRTUAL MEMORY, every program would need to know the actual,
   physical RAM address of everything it touches -- and if two programs
   both tried to use the same physical address, disaster. This was a
   real problem in early computing.

   WITH VIRTUAL MEMORY, every process gets its OWN, PRIVATE address
   space -- typically the full range a 64-bit pointer can express. When
   your program reads or writes address `0x7fff1234`, the CPU's MEMORY
   MANAGEMENT UNIT (MMU) -- dedicated hardware, working with page tables
   the kernel maintains -- translates that VIRTUAL address into whatever
   PHYSICAL RAM address it actually corresponds to, if any, completely
   transparently to your program:

     Process A's virtual 0x1000  ->  physical RAM address 0x7A2000
     Process B's virtual 0x1000  ->  physical RAM address 0x3F1000
                                     (a DIFFERENT physical location --
                                      this is the whole isolation
                                      guarantee)

   THIS ALSO ENABLES SOME GENUINELY USEFUL TRICKS:
     - two processes can SHARE the same physical memory (a shared
       library like libc) while each believes it has its own private
       copy at its own virtual address.
     - a virtual address doesn't need to be backed by RAM AT ALL, right
       now -- it can be backed by disk (Chapter 11's paging), or not
       backed by anything until it's actually touched (this is how
       `malloc()`-ing a huge amount of memory can succeed instantly:
       nothing physical is allocated until you actually write to it).

Real-world example

   Address Space Layout Randomization (ASLR) is a direct SECURITY
   application of virtual memory, standard in every modern OS since the
   mid-2000s (mainline Linux since kernel 2.6.12, 2005). Because a
   process's virtual addresses are just a mapping the kernel controls,
   the kernel can RANDOMISE where key regions (the stack, the heap,
   shared libraries) land in a process's virtual address space EACH TIME
   it runs. This specifically defeats a huge class of MEMORY-CORRUPTION
   EXPLOITS that rely on knowing exactly where, in memory, a piece of
   attacker-useful code or data will be -- without virtual memory's
   indirection, there would be nothing TO randomise; physical addresses
   would need to change, which is far harder to do safely. This is a
   genuinely important, still-active area of security engineering (ASLR
   bypasses and defeats are an ongoing arms race, referenced throughout
   the companion security guides in this wiki) built entirely on top of
   the OS concept this chapter teaches.

Try it yourself

# See your own shell's virtual memory map -- notice how large and sparse
# the address ranges are compared to your machine's actual physical RAM
cat /proc/self/maps | head -20

# Compare virtual size (VSZ) to actual resident memory (RSS) for a
# running process -- VSZ is often dramatically larger
ps -eo pid,vsz,rss,cmd | sort -k2 -n -r | head -5

# See ASLR in action: run the same program twice, watch a library's
# load address change between runs
for i in 1 2; do
  grep libc /proc/self/maps 2>/dev/null | head -1
done
# (run in two separate shell invocations for a clean comparison, e.g.:
#  bash -c 'grep libc /proc/self/maps | head -1'  -- run this twice)

Common mistakes

  • "Virtual memory means slower memory." The translation happens in dedicated hardware (the MMU) and is extremely fast — the SLOW part only happens when a virtual address isn't currently backed by RAM at all (Chapter 11's page fault).
  • Assuming a process's memory usage equals its virtual address space size. VSZ (virtual size) can be enormous and mostly meaningless; RSS (resident set size — memory ACTUALLY in RAM right now) is usually the number you care about.
  • Thinking two processes literally cannot share memory. They can, on purpose (shared libraries, mmap-based shared memory, Chapter 19) — what virtual memory prevents is ACCIDENTAL, unintended sharing.

Check yourself

  1. What problem does virtual memory solve, in one sentence?
  2. What translates a virtual address into a physical one, and where does that translation information live?
  3. Why does ASLR depend on virtual memory existing at all?

Further reading

  • Book (free): OSTEP, the entire "Virtualization: Memory" section — the clearest available walkthrough of address translation, from first principles.
  • Reference: man 5 proc (the /proc/[pid]/maps section).
  • Article: "A Brief History of ASLR" or similar retrospectives on why and when major OSes adopted it.

Generated from real-life-os-guide.md · 8 Oct 2026 16:36