What is RLIMIT_MEMLOCK?
RLIMIT_MEMLOCK limits the number of bytes of virtual memory a process may lock into physical memory (RAM), preventing those pages from being swapped out to disk. This is a BSD-derived limit — not in SUSv3 — but available on Linux and the BSDs.
Locking memory is important in real-time and embedded contexts: swapping a page out and back introduces unpredictable latency spikes. By locking critical pages (like your BLE protocol handler or audio buffer), you guarantee they are always in RAM.
Which System Calls Are Affected
RLIMIT_MEMLOCK governs how much memory can be locked. The affected calls are:
Locks a specific address range. Fails with ENOMEM if the amount to lock exceeds RLIMIT_MEMLOCK.
Locks all current and/or future pages. Uses MCL_CURRENT and/or MCL_FUTURE flags.
The MAP_LOCKED flag in mmap() also counts against RLIMIT_MEMLOCK.
Locking System V shared memory segments also counts against this limit.
The MCL_FUTURE Complication
When mlockall(MCL_FUTURE) is called, it tells the kernel: “lock every page I map in the future too, not just the pages I have now.” This creates a latent constraint: any subsequent call to brk(), sbrk(), mmap(), or mremap() that would push the locked-memory total past RLIMIT_MEMLOCK will fail.
/* MCL_FUTURE: lock all future pages too */
mlockall(MCL_FUTURE);
/* Any of these may later fail with ENOMEM if
the new pages would exceed RLIMIT_MEMLOCK: */
malloc(large_amount); /* internally calls sbrk()/mmap() */
mmap(NULL, size, ...); /* anonymous mapping */
mremap(old, old_sz, new_sz, ...); /* expand mapping */
mlockall(MCL_CURRENT | MCL_FUTURE) at startup to guarantee all code and data is always in RAM. This requires either root privileges or a sufficiently high RLIMIT_MEMLOCK.Code Example — mlock() and RLIMIT_MEMLOCK
#define _GNU_SOURCE
#include
#include
#include
#include
#include <sys/mman.h>
#include <sys/resource.h>
int main(void)
{
struct rlimit rl;
/* Check current memlock limit */
getrlimit(RLIMIT_MEMLOCK, &rl);
printf("RLIMIT_MEMLOCK: soft=%lld hard=%lld bytes\n",
(long long)rl.rlim_cur, (long long)rl.rlim_max);
/* Allocate 1 MB and try to lock it */
size_t sz = 1024 * 1024;
void *buf = mmap(NULL, sz, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (buf == MAP_FAILED) { perror("mmap"); exit(1); }
/* Touch all pages so they are faulted in */
memset(buf, 0, sz);
/* Lock: will fail with ENOMEM if sz > RLIMIT_MEMLOCK soft */
if (mlock(buf, sz) == -1) {
if (errno == ENOMEM)
printf("mlock failed: ENOMEM (RLIMIT_MEMLOCK exceeded)\n");
else if (errno == EPERM)
printf("mlock failed: EPERM (need root or higher limit)\n");
else
perror("mlock");
} else {
printf("Locked 1 MB in RAM successfully\n");
munlock(buf, sz);
}
munmap(buf, sz);
return 0;
}
/* Compile: gcc -o memlock_demo memlock_demo.c
Note: unprivileged processes on many systems have
RLIMIT_MEMLOCK = 64 KB, so locking 1 MB will fail
unless you are root or the limit is raised. */
Interview Questions
Real-time applications lock all their memory to prevent page faults. A page fault causes the kernel to read a page from disk (major fault) or remap a cached page (minor fault). Either case introduces unpredictable latency that can violate real-time deadlines. By calling mlockall(MCL_CURRENT | MCL_FUTURE) at startup, all code and data pages are guaranteed to be in RAM — eliminating fault-induced jitter.
ENOMEM. The mlock() call fails and errno is set to ENOMEM. Note that EPERM is returned if the process lacks the CAP_IPC_LOCK capability and RLIMIT_MEMLOCK is 0.
MCL_FUTURE. When mlockall(MCL_FUTURE) is called, every subsequent memory mapping (brk(), mmap(), mremap()) will be automatically locked into RAM. If any such call would push the locked total past RLIMIT_MEMLOCK, it fails with ENOMEM.
No. It is BSD-derived and absent from SUSv3. It is available on Linux and the BSDs but not on all UNIX systems. Code using RLIMIT_MEMLOCK is therefore not portable to all POSIX-compliant systems.
