Copy-on-write (CoW) makes copying cheap by postponing the copy. Two owners initially reference the same physical data. The system copies only when one owner mutates it.
That is an excellent default for process creation, filesystem snapshots, and immutable data structures. It is not free. CoW moves cost from creation time to the first write, where latency and memory growth are often less visible.
The operating-system case #
After fork(), parent and child have separate virtual address spaces whose page-table entries can initially refer to the same physical pages. Those mappings are protected against direct writes. When either process writes, the CPU raises a page fault; the kernel allocates a new page, copies content, and updates the writer’s mapping.
before write after child writes
parent VA --+ parent VA ---> page A
+-> page A
child VA --+ child VA ---> page B (copy)Linux page tables translate process virtual addresses into physical addresses. CoW works by changing mappings and permissions, not by teaching application objects to clone themselves.
Why production latency surprises teams #
Consider a large in-memory service that forks a child for a snapshot. Fork can return quickly, but pages modified while the child remains alive must be copied. A write-heavy workload can produce:
- bursts of minor page faults;
- rapid resident-memory growth;
- extra memory bandwidth consumption;
- allocator and page-table work;
- an out-of-memory kill if headroom was planned from steady-state RSS.
The snapshot duration becomes part of the write-amplification budget. A slower child extends the interval during which mutations create private copies.
The same shape appears above the OS. A CoW B-tree copies nodes along an update path. A filesystem snapshot keeps old blocks alive when new versions are written. The unit differs—page, node, block—but the operational question is the same: how much changes while old readers retain the previous version?
Capacity model #
A useful upper-bound model is:
peak memory ~= base working set
+ unique pages dirtied during overlap
+ page tables and process overhead
+ safety marginDo not estimate the second term from average write throughput alone. Measure distinct pages dirtied during the snapshot window. A workload repeatedly changing one hot page behaves differently from one touching the entire heap.
Production checks #
| Risk | Evidence to collect |
|---|---|
| first-write latency | minor faults and tail latency |
| memory expansion | RSS and dirty-page growth during overlap |
| slow snapshot | duration distribution and bytes produced |
| workload sensitivity | unique pages dirtied, not just write count |
| failure recovery | behavior when snapshot child exits or is killed |
Run load tests with the real mutation pattern and the longest expected snapshot time. Confirm the service has headroom during deployment, compaction, and backup overlap—not only when each runs alone.
Trade-offs #
Eager copies make creation predictably expensive and reserve capacity early. CoW makes common read-mostly paths efficient but produces workload-dependent first-write costs. Immutable persistent structures provide controlled sharing but add indirection and reclamation work. Log-based snapshots avoid some page copying while introducing replay and retention requirements.
Use CoW when sharing is likely to outlive few mutations. When most of the working set will be rewritten before the old view disappears, the optimization can become deferred full-copy cost with a less convenient latency profile.