Is It Possible to Lock a Process's Memory in Linux to Avoid Swapping?
A Guide to Controlling Process Memory Swapping in Linux
Introduction
In Linux, memory management is a critical aspect of system performance. The kernel uses a swap space to move infrequently accessed pages from RAM to disk, freeing up memory for active processes. However, certain applications—such as real-time systems, high-frequency trading platforms, or security-sensitive processes—may require their memory to remain in RAM to ensure optimal performance or prevent data leaks.
This guide explores how to control memory swapping for specific processes in Linux using system calls like mlock
, mlockall
, and madvise
, along with practical examples and verification techniques.
Table of Contents
Understanding Swapping in Linux
Locking Memory with
mlock
andmlockall
System Call Overview
Code Examples
Verifying Locked Memory
Optimizing Paging with
madvise
Command-Line Tools and Wrappers
Resource Limits and Capabilities
Advanced Methods: cgroups and Kernel Parameters
Troubleshooting Common Issues
Use Cases and Best Practices
Conclusion
1. Understanding Swapping in Linux
What is Swapping?
When physical RAM is exhausted, the Linux kernel moves inactive memory pages to a designated swap area (disk space). This process is transparent to applications but introduces latency if swapped-out pages are accessed later.
Why Control Swapping?
Performance: Real-time applications cannot tolerate disk I/O delays.
Security: Sensitive data (e.g., encryption keys) must not leak to disk.
Predictability: Critical processes need guaranteed RAM allocation.
2. Locking Memory with mlock
and mlockall
System Call Overview
mlock
/munlock
mlock(const void *addr, size_t len)
: Locks a specific memory region into RAM.munlock
: Unlocks the region.
mlockall
/munlockall
mlockall(int flags)
: Locks all current and future process memory.Flags:
MCL_CURRENT
(lock existing pages),MCL_FUTURE
(lock future mappings).
munlockall
: Unlocks all memory.
Code Example: Locking a Memory Region
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
int main() {
const size_t size = 1024 * 1024; // 1 MB
char *buffer = malloc(size);
if (buffer == NULL) {
perror("malloc");
return 1;
}
// Touch the memory to ensure it's mapped
for (size_t i = 0; i < size; i++) {
buffer[i] = 'A';
}
// Lock the memory region
if (mlock(buffer, size) == -1) {
perror("mlock");
return 1;
}
printf("Memory locked at %p. Press Enter to exit...\n", buffer);
getchar();
munlock(buffer, size);
free(buffer);
return 0;
}
Compilation and Execution
gcc lock_memory.c -o lock_memory
sudo ./lock_memory # Requires CAP_IPC_LOCK or root
Expected Output
Memory locked at 0x7f8e6c001000. Press Enter to exit...
Verification with pmap
While the program is running, use pmap
to inspect memory mappings:
pmap -X $(pidof lock_memory)
Look for the Kbytes
column; locked memory shows mlk
in the Mode
field.
Code Example: Locking All Process Memory
#include <stdio.h>
#include <sys/mman.h>
int main() {
// Lock all current and future memory
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
perror("mlockall");
return 1;
}
printf("All memory locked. Press Enter to exit...\n");
getchar();
munlockall();
return 0;
}
3. Optimizing Paging with madvise
The madvise
system call advises the kernel on how to handle memory access patterns. While it doesn’t lock memory, it optimizes swapping behavior.
Common Flags:
MADV_WILLNEED
: Prefetch pages into RAM.MADV_DONTNEED
: Free pages immediately.MADV_SEQUENTIAL
: Expect sequential access (aggressive read-ahead).MADV_RANDOM
: Disable read-ahead.
Example: Advising Sequential Access
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
int main() {
const size_t size = 1024 * 1024;
char *buffer = malloc(size);
// Advise the kernel about sequential access
if (madvise(buffer, size, MADV_SEQUENTIAL) == -1) {
perror("madvise");
return 1;
}
printf("Advice set for sequential access.\n");
free(buffer);
return 0;
}
4. Command-Line Tools and Wrappers
Using a Wrapper to Lock Memory for Any Process
The following C program spawns a child process that locks its memory before executing a command:
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <command>\n", argv[0]);
return 1;
}
pid_t pid = fork();
if (pid == 0) { // Child
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
perror("mlockall");
return 1;
}
execvp(argv[1], &argv[1]);
} else if (pid > 0) { // Parent
printf("Process %d started with locked memory.\n", pid);
} else {
perror("fork");
return 1;
}
return 0;
}
Usage
gcc mlock_wrapper.c -o mlock_wrapper
sudo ./mlock_wrapper ./my_critical_app
5. Resource Limits and Capabilities
Bypassing RLIMIT_MEMLOCK
The RLIMIT_MEMLOCK
limit restricts how much memory a user can lock. View it with:
ulimit -l
Adjusting Limits Temporarily
sudo sh -c "ulimit -l unlimited && exec su $USER"
Permanent Adjustments
Edit /etc/security/limits.conf
:
* hard memlock unlimited
* soft memlock unlimited
Granting CAP_IPC_LOCK
Avoid running as root by granting the capability:
sudo setcap cap_ipc_lock+ep /path/to/program
6. Advanced Methods: cgroups and Kernel Parameters
cgroups v2 Memory Control
Disable swapping for a cgroup:
mkdir /sys/fs/cgroup/mycgroup
echo "+memory" > /sys/fs/cgroup/cgroup.subtree_control
echo 0 > /sys/fs/cgroup/mycgroup/memory.swap.max
echo $$ > /sys/fs/cgroup/mycgroup/cgroup.procs
Tuning vm.swappiness
Globally adjust swap tendency (0–100):
sysctl vm.swappiness=10
7. Troubleshooting Common Issues
Error: Cannot allocate memory
Cause: Exceeded
RLIMIT_MEMLOCK
or physical RAM.Fix: Increase limits or reduce locked memory.
Error: Operation not permitted
Cause: Missing
CAP_IPC_LOCK
or root access.Fix: Grant capability or run as root.
8. Use Cases and Best Practices
When to Lock Memory
Real-Time Systems: Avoid nondeterministic swap delays.
Sensitive Data: Prevent exposure via swap files.
High-Performance Apps: Ensure memory-intensive tasks stay in RAM.
Best Practices
Lock only essential memory regions.
Monitor system RAM usage to avoid OOM scenarios.
Prefer
mlock2
withMLOCK_ONFAULT
for on-demand locking.
9. Conclusion
Controlling memory swapping in Linux is vital for performance-critical and security-sensitive applications. By leveraging mlock
, mlockall
, and madvise
, developers can ensure memory residency and optimize paging behavior. Always balance locked memory with system stability and adhere to resource limits to maintain overall system health.