Cloud & Infrastructure · Sensei

The Copy That Does Not Happen Until You Write

Copy-on-write — why fork() on a 2 GB process returns in under a millisecond, and what you pay for it later.
Technical poster: copy-on-write before/after pointer diagram and page-fault sequence

Core concept

Several processes share one instance of the data instead of each getting a private copy. The duplicate is created at the exact moment a process tries to modify it — not a moment sooner.

Underneath the friendly word “copy”: only the page table is duplicated, not the pages. Both processes point at the same physical frames, every shared page is marked read-only, and the copy is instant regardless of size. You pay per page touched, not per byte owned.

Key components

the illusion

Duplicated page table

Two sets of virtual → physical mappings over one set of physical frames. Cheap, small, O(mappings) — not O(bytes).

the tripwire

Read-only marking

Every shared page loses its write permission. That flag is the whole enforcement mechanism — there is no bookkeeping thread watching you.

the interrupt

Page fault on write

The CPU traps the write instruction mid-flight and hands control to the kernel. The instruction has not committed yet, so it can be resumed.

the granularity

One 4 KB page

The kernel copies a single page, flips it writable for the writer only, and leaves everyone else on the original. Cost scales with pages written.

How it works — intercept, copy, leave the original alone

Before the write Process A → Shared Data v1 Process B → Shared Data v1 one box, marked READ-ONLY
After B writes Process A → Shared Data v1 unchanged Process B → Private Copy v2 one page copied, not the dataset
  1. A process issues a write to a shared, read-only page.
  2. The processor raises a page fault — the write is intercepted before it lands.
  3. The kernel allocates one fresh 4 KB page and copies just that page’s contents.
  4. It remaps the writer to the new page and flips it to writable.
  5. The faulting instruction resumes. Every other process still sees the original, untouched.

Where it shows up

  • Operating systems — fork(). Duplicating a 2 GB process returns in well under a millisecond, because nothing was actually copied yet.
  • Database & filesystem snapshots. ZFS and Btrfs snapshot instantly by sharing blocks and diverging only on write.
  • Virtual machines and VM snapshots. Boot many VMs off one base image; each one only materialises the pages it dirties.
  • Version control & background saves. Redis forks a child to write its snapshot to disk while the parent keeps serving traffic.

⚠ Falsification — test this before you trust it

The cost is deferred, not removed, and it arrives as latency at the worst possible moment.

A Redis instance that forks to save while write traffic is heavy can end up copying nearly every page anyway. Peak memory approaches double the dataset and the host starts swapping — the “free” copy becomes the most expensive operation of the day.

The experiment: fork under a write-heavy load and watch resident set size climb, rather than assuming the copy stayed free. If RSS tracks toward 2× your dataset, you have found the deferred bill.

Checkpoint — answer before you move on

  1. A process holding 2 GB calls fork() and returns in under a millisecond. What was actually duplicated, and what was not? Hint: name the structure that was copied, and what makes the pages themselves safe to share.
  2. Nothing watches for writes, yet the write is caught. Trace the exact sequence from the write instruction to its resumption. Hint: five beats — permission flag, hardware trap, allocation size, remap, resume.
  3. Your Redis host has 8 GB of RAM and a 5 GB dataset, and it swaps every time a background save runs. Why, and what measurement would confirm it? Hint: what happens to shared pages when the parent keeps taking writes during the save?