POSIX Allocations

POSIX also provides mechanisms for managing memory mapping more directly. Specifically, the two functions we will look at are mmap and munmap`.

  • void *mmap(void *addr, size_t len, int prot, int flags, int filedes, off_t off)

  • int munmap(void *addr, size_t len);

The mmap function can be used to map files directly into memory for extremely efficient data access, and the munmap function is used to release an existing mapping. Recall that each read or write operation on a file normally goes through a costly read() or write() system call–even the standard library I/O methods are wrappers around these system calls. On the other hand, if a file is mapped directly into memory, then a program can access its data directly without any system calls. When an attempt is made to access a portion of the file that isn’t currently loaded, the kernel’s page fault handler loads that portion into memory, with less overhead than an equivalent read() call for the same amount of data.

Memory mapping is powerful and supports several configurations, many of which are extensions offered by particular operating systems, are too extensive to discuss here–refer to the manual on a particular system for more detailed information. In short, the addr and len arguments specify the address range over which the mapping should be placed; addr may be null, in which case the map is assigned a location automatically. The prot argument is a set of flags that specify a mapping’s protections–read, write, execute, and none. The flags argument specifiers the mapping’s behavior–shared or private. A shared mapping causes writes to the mapped memory region to update the underlying file, while a private mapping only updates the program’s copy of the data. The filedes specifies the file to be mapped, and off specifies the offset within the file to begin the mapping at.

One extension which Linux offers, is the ability to map anonymously by passing the appropriate flags argument. An anonymous memory mapping does not have a file-backing, and is used to manually allocate blocks of memory. This would be used, for example, as an alternative to malloc if one desired much finer control over the allocation, or even to create a custom implementation of an allocator library.

Lastly, memory mappings are used for high performance inter-process communication. When two processes have the same region of memory mapped in a shared configuration, they can share data with each other directly, without the kernel mediating the exchange through system calls. Child processes inherit mappings from their parents, but two unrelated processes can also gain a shared mapping through mapping the same file.