How Processes Share Memory Without Copying (Visual)
How Processes Share Memory Without Copying (Visual)
A visual explanation of how two separate processes can access the same bytes without copying a payload between them.
It covers virtual memory, page tables, physical frames, shm_open, mmap(MAP_SHARED), lazy allocation, copy-on-write, shared libraries, memory-mapped files, Redis snapshots, and Dirty COW.
Virtual Memory and Page Tables
Each process has its own virtual address space. The operating system maintains a page table for each process that maps virtual pages to physical frames in RAM. When two processes map different virtual addresses to the same physical frame, they share that memory without copying.
Shared Memory with shm_open and mmap
The POSIX shared memory API allows processes to create and map shared memory segments:
- Process A calls
shm_open("/myregion", O_CREAT | O_RDWR, 0666)to create or open a shared memory object. - Process A calls
ftruncate(fd, size)to set the size. - Process A calls
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)to map it into its address space. - Process B opens the same shared memory object with
shm_open("/myregion", O_RDWR, 0666). - Process B calls
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0).
Both processes now have virtual pages pointing to the same physical frames. Writes by either process are immediately visible to the other.
Lazy Allocation and Copy-on-Write
When a process calls mmap(MAP_SHARED), the kernel does not immediately allocate physical pages. Instead, it uses lazy allocation:
- The page table entries are marked as not present.
- When the process first accesses a page, a page fault occurs.
- The kernel then allocates a physical frame and updates the page table.
Copy-on-write (COW) is a related optimization used with MAP_PRIVATE mappings. When a process forks:
- The child inherits the parent's page tables.
- All pages are marked read-only and shared.
- When either process writes to a page, a page fault triggers a copy of that page to a new physical frame.
Shared Libraries
Shared libraries (.so files) use memory-mapped files with MAP_SHARED. When multiple processes load the same library:
- The kernel maps the library's code pages from the same physical frames.
- Each process has its own virtual addresses, but they point to the same physical memory.
- This saves both RAM and disk cache.
Memory-Mapped Files
A file can be mapped into memory with mmap(MAP_SHARED):
- The file's contents are loaded into physical frames on demand.
- Multiple processes mapping the same file share those physical frames.
- Writes to the mapped memory are eventually written back to the file by the kernel.
Redis Snapshots
Redis uses fork() to create a child process for saving snapshots (RDB files). The child inherits the parent's entire memory layout via copy-on-write:
- Initially, the child shares all physical pages with the parent.
- As the parent continues serving requests, it modifies pages, triggering COW copies.
- The child writes the snapshot from its frozen view of memory, without copying the entire dataset upfront.
Dirty COW
Dirty COW (CVE-2016-5195) was a privilege escalation vulnerability in the Linux kernel's copy-on-write implementation. It allowed a local attacker to write to read-only memory mappings by racing a COW page fault against a write to the underlying file-backed page. The exploit used mmap(MAP_SHARED) combined with madvise(MADV_DONTNEED) to trigger the race condition, gaining write access to pages that should have remained read-only.
Comments
No comments yet. Start the discussion.