Photo by Fredy Jacob on Unsplash

Memory-Mapped Files: When the Filesystem Becomes RAM


Memory-mapped files represent one of the more elegant intersections between storage and memory in modern operating systems. By mapping file contents directly into a process’s address space, they eliminate explicit read and write calls while letting the OS handle all the complexity of moving data between disk and RAM.

The Core Mechanism

When you memory-map a file, the operating system creates a mapping between a region of virtual memory and the file’s contents on disk. From the application’s perspective, the file appears as a contiguous array of bytes in memory. Reading from this memory region transparently loads data from disk on demand. Writing to it eventually flushes changes back to the filesystem.

This works through the same virtual memory paging system that manages all process memory. The OS doesn’t load the entire file into RAM upfront. Instead, it divides the file into page-sized chunks (typically 4KB). When your code accesses an address that hasn’t been loaded yet, a page fault occurs, the kernel fetches that page from disk, and execution continues. Recently accessed pages stay in RAM while unused ones get evicted under memory pressure.

Zero-Copy Data Access

The primary advantage is eliminating redundant copying. With traditional file I/O, reading data involves copying bytes from the kernel’s page cache into your process’s buffer. Writing means copying from your buffer back into the kernel. Memory-mapped files skip these copies entirely. Your process and the kernel share the same physical pages, so reading or writing is just memory access.

This matters most for large files where copy overhead becomes significant. Databases, for instance, commonly use memory-mapped files for data storage. The database engine can treat on-disk data structures like in-memory ones, letting the OS manage which portions stay resident in RAM. The same applies to search indexes, analytics engines, and any system working with datasets larger than available memory.

Shared Memory and IPC

Memory-mapped files also provide a straightforward mechanism for inter-process communication. Multiple processes can map the same file into their address spaces, giving them a shared memory region. Changes made by one process become visible to others, though synchronization primitives are still needed to avoid race conditions.

Some systems take this further by mapping anonymous memory (not backed by any persistent file) to create pure shared memory regions. This is how many shared memory APIs work under the hood.

The Trade-offs

Memory-mapped files aren’t universally superior to explicit I/O. Error handling becomes more complex since I/O errors manifest as segmentation faults rather than return codes. A page fault might block your thread unpredictably if the data isn’t cached, making latency harder to reason about. You also lose fine-grained control over when I/O happens—the OS decides based on its own paging algorithms.

Sequential access patterns work well with traditional streaming I/O and readahead, while truly random access favors memory mapping. Writes through memory-mapped files can be harder to reason about. Changes don’t necessarily reach disk immediately; you need explicit sync operations (like msync) to force durability.

Real-World Applications

Beyond databases, memory-mapped files power log processing tools that need random access into massive log files without loading everything into RAM. Game engines use them for asset streaming, mapping texture and model data on demand. Build systems map large dependency graphs. Even the dynamic linker uses memory mapping to load shared libraries into process address space.

The technique also enables efficient file format designs. File formats can include internal indexes and metadata structures that applications access directly through pointers, without parsing or deserializing. This is why formats like memory-mapped B-trees or memory-mapped hash tables can outperform traditional file-based alternatives.

Platform Differences

The core concept is consistent across Unix-like systems (via mmap) and Windows (via CreateFileMapping and MapViewOfFile), though details differ. Some systems support huge pages for memory mappings, reducing TLB pressure for very large files. Others offer flags controlling caching behavior, prefetching, or memory locking.

Memory-mapped files represent a pragmatic acknowledgment that disk and memory form a continuum rather than a binary distinction. By letting the OS manage that continuum automatically, applications gain simplicity and performance—provided they understand the model’s constraints.