9.1 Copy-on-Write (CoW) Mechanism
The problem: Sometimes two processes (or a process and a new copy of itself) must start with identical memory contents. Copying all that memory right away would waste time and RAM, because most of it may never change.
The solution: Copy-on-Write lets two (or more) virtual mappings point to the exact same physical pages, marked read-only, for as long as nobody changes them. The instant one side tries to write to a shared page, the MMU notices a write to a read-only page and hands control to the OS (a trap). Only then does the OS make a real, private copy of just that one page for the writer. The other side is left completely untouched.
Analogy: Two students share one textbook. As long as both only read, one copy is enough. The moment one wants to scribble in it, they photocopy that one page for themselves.
Before any write — shared:
Process A's page ──┐
├──► Same physical page (marked read-only)
Process B's page ──┘
Process B writes to its page:
│
▼
MMU detects write to a read-only page → OS trap
│
▼
OS copies the page — now:
Process A's page ────────► Original physical page (unchanged)
Process B's page ────────► New private copy (B's write applied here)
Why this is efficient: The costly work (really copying data) happens only for the few pages that ever get changed. Pages that are only read are shared forever, at no extra memory cost beyond the one physical copy.
9.2 When CoW Is Used
Process creation (fork on Unix-like systems): When a process makes a near-identical copy of itself, the child shares every page with the parent through CoW, instead of copying the parent's whole address space up front. Many new processes immediately replace their memory anyway (for example by loading a different program), so this avoids a huge amount of wasted copying. (Windows does not use fork the same way Unix does, but the CoW mechanism is used widely elsewhere in Windows — including the DLL-loading case below.)
DLL loading: When several processes load the same DLL (say kernel32.dll, loaded by almost every process), Windows maps the DLL's code pages as shared and read-only in all of them. One physical copy of the DLL's code serves every process. If a process needs to patch or relocate part of that memory for itself, only then does CoW step in and give that process a private page.
Process A ──┐
Process B ──┼──► One shared, read-only copy of kernel32.dll's code in RAM
Process C ──┘
(instead of 3 separate physical copies of the same code)
Why this matters: It is a big reason Task Manager's per-process memory numbers can mislead if read naively. Several processes may each show memory for the same shared DLL, yet the real RAM cost of that DLL is paid once, not once per process.
9.3 Shared Memory Between Processes
What it is: A deliberate, explicit tool (different from the CoW cases above, which are about internal efficiency). It lets two or more unrelated but cooperating processes map the same physical memory into both of their address spaces. They can then read and write shared data directly, without copying it back and forth.
Process A's address space: ... [shared region] ...
│
▼ same physical memory
Process B's address space: ... [shared region] ...
This is one of several Inter-Process Communication (IPC) methods — ways for programs to talk to each other. (The others — pipes, sockets, message passing — are covered in Chapter 9.) Shared memory is usually the fastest IPC method, because the data does not need to be copied through the kernel at all: both processes read and write the same physical bytes. The trade-off is that the processes need their own system to take turns (see Chapter 10's discussion of mutexes and other synchronization tools), so that they do not corrupt the data when both use it at the same moment.
9.4 Memory-Mapped Files
What it is: A technique where a file's contents (from storage) are mapped straight into a process's virtual address space. The program can then read and write the file just by reading and writing memory — with ordinary pointer or array access — instead of calling explicit file read/write functions.
Without memory mapping:
ReadFile(handle, buffer, size) → explicit copy from OS file
cache into the program's buffer
With memory mapping:
file is mapped at virtual address 0x10000000
accessing memory at 0x10000000 directly reads the file's bytes
(the OS handles bringing the right page in from disk on demand,
via the exact same page fault mechanism from Section 5.2)
Why this is powerful:
- Lazy loading: Only the parts of the file that are actually used get read from storage. A huge file can be "mapped" instantly, and single pages are brought in only when touched
- Shared access: Many processes can map the same file and automatically share the same physical pages (the same mechanism as Section 9.3). This is exactly how Windows loads executable and DLL files: a program's code segment (Section 6.4) is itself a memory-mapped view of the .exe/.dll file on disk
- Simplicity: Code that treats a file as an in-memory array is often simpler and faster than managing read/write calls and buffers by hand
The link to this whole chapter: Memory-mapped files are a clear example of virtual memory's real power. A "memory address" does not have to mean RAM that was filled by a normal allocation. It can quietly mean a file on disk, with the page fault mechanism bridging the two whenever needed.
Summary
| Topic | Remember this |
|---|---|
| Copy-on-Write | Share pages read-only; copy only the one page that is written |
fork / process creation | Child shares the parent's pages through CoW |
| DLL sharing | One physical copy of a DLL's code serves every process |
| Shared memory | Cooperating processes map the same physical memory; fastest IPC, needs synchronization |
| Memory-mapped file | A file appears as memory; pages are loaded on demand through page faults |