8.8 The mlock Family: Locking Physical Memory

The mlock family of system calls allows a program to lock some or all of its address space into physical memory. This prevents Linux from paging this memory to swap space, even if the program hasn't accessed it for a while.

A time-critical program might lock physical memory because the time delay of paging memory out and back may be too long or too unpredictable. High-security applications may also want to prevent sensitive data from being written out to a swap file, where they might be recovered by an intruder after the program terminates.

Locking a region of memory is as simple as calling mlock with a pointer to the start of the region and the region's length. Linux divides memory into pages and can lock only entire pages at a time; each page that contains part of the memory region specified to mlock is locked. The getpagesize function returns the system's page size, which is 4KB on x86 Linux.

For example, to allocate 32MB of address space and lock it into RAM, you would use this code:

 
const int alloc_size = 32 * 1024 * 1024; 
char* memory = malloc (alloc_size); 
mlock (memory, alloc_size); 

Note that simply allocating a page of memory and locking it with mlock doesn't reserve physical memory for the calling process because the pages may be copy-on-write. [5] Therefore, you should write a dummy value to each page as well:

[5] Copy-on-write means that Linux makes a private copy of a page of memory for a process only when that process writes a value somewhere into it.

 
size_t i; 
size_t page_size = getpagesize (); 
for (i = 0; i < alloc_size; i += page_size) 
  memory[i] = 0; 

The write to each page forces Linux to assign a unique, unshared memory page to the process for that page.

To unlock a region, call munlock, which takes the same arguments as mlock.

If you want your program's entire address space locked into physical memory, call mlockall. This system call takes a single flag argument: MCL_CURRENT locks all currently allocated memory, but future allocations are not locked; MCL_FUTURE locks all pages that are allocated after the call. Use MCL_CURRENT|MCL_FUTURE to lock into memory both current and subsequent allocations.

Locking large amounts of memory, especially using mlockall, can be dangerous to the entire Linux system. Indiscriminate memory locking is a good method of bringing your system to a grinding halt because other running processes are forced to compete for smaller physical memory resources and swap rapidly into and back out of memory (this is known as thrashing). If you lock too much memory, the system will run out of memory entirely and Linux will start killing off processes.

For this reason, only processes with superuser privilege may lock memory with mlock or mlockall. If a nonsuperuser process calls one of these functions, it will fail, return –1, and set errno to EPERM.

The munlockall call unlocks all memory locked by the current process, including memory locked with mlock and mlockall.

A convenient way to monitor the memory usage of your program is to use the top command. In the output from top, the SIZE column displays the virtual address space size of each program (the total size of your program's code, data, and stack, some of which may be paged out to swap space). The RSS column (for resident set size) shows the size of physical memory that each program currently resides in. The sum of all the RSS values for all running programs cannot exceed your computer's physical memory size, and the sum of all address space sizes is limited to 2GB (for 32-bit versions of Linux).

Include <sys/mman.h> if you use any of the mlock system calls.