本文目录导读:

在 Linux 系统中,锁定内存页以防止其被交换到磁盘(swap)上,通常使用 mlock() 或 mlockall() 系统调用,以下是详细的方法和注意事项:
核心系统调用
a) mlock():锁定指定的内存区域
#include <sys/mman.h> int mlock(const void *addr, size_t len);
- 作用:锁定从
addr开始的len字节的内存页,使其常驻物理内存。 - 示例(锁定一个缓冲区):
char *buf = malloc(4096); if (mlock(buf, 4096) == -1) { perror("mlock failed"); }
b) mlockall():锁定进程的全部内存页
#include <sys/mman.h> int mlockall(int flags);
- flags 可选值:
MCL_CURRENT:锁定当前已分配的所有内存页。MCL_FUTURE:锁定未来分配的所有内存页(例如后续的malloc、mmap等)。MCL_ONFAULT(Linux 4.4+):仅在页被访问时锁定(按需锁定,避免一次性锁定大量未使用内存)。
- 示例(锁定所有当前和未来的内存):
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { perror("mlockall failed"); }
c) 解锁:munlock() 或 munlockall()
munlock(addr, len):解锁指定区域。munlockall(void):解锁当前进程的所有锁定的内存。
权限与限制
- 需要 CAP_IPC_LOCK 能力:非 root 用户默认不能锁定任意大量内存,可以通过以下方式授权:
- 以 root 运行程序。
- 为用户设置
ulimit -l unlimited(临时)或配置/etc/security/limits.conf(永久):username hard memlock unlimited username soft memlock unlimited
- 受 RLIMIT_MEMLOCK 限制:
ulimit -l设置单个用户可锁定的最大内存量。
应用场景与注意事项
适用场景
- 实时系统:需要保证关键数据始终在物理内存中,避免换页延迟。
- 密码/密钥处理:防止敏感数据被交换到磁盘(虽然仍有其他攻击面)。
- 大数据处理:锁定频繁访问的缓存或数据结构。
注意事项
- 内存耗尽风险:锁定过多内存会导致系统内存不足,甚至 OOM(Out-Of-Memory)杀进程。
- 子进程行为:锁定的内存在
fork()时不会被子进程继承(子进程需重新调用mlock)。 - 性能影响:锁定内存会减少可用于文件缓存的内存,可能影响整体系统性能。
- 动态内存管理:如果使用
malloc后调用mlock,确保锁定的地址和长度正确(malloc可能多分配页对齐的内存)。
检查已锁定的内存
查看 /proc/[pid]/status 中的 VmLck 字段:
grep VmLck /proc/1234/status
或者用 pmap:
pmap -x 1234 | grep locked
完整示例(C语言)
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
int main() {
size_t size = 1024 * 1024; // 1 MB
char *buf = malloc(size);
// 锁定内存
if (mlock(buf, size) == -1) {
perror("mlock");
exit(1);
}
// 访问内存(触发缺页,确保锁定生效)
memset(buf, 0, size);
printf("Memory locked. PID: %d\n", getpid());
printf("Check with: grep VmLck /proc/%d/status\n", getpid());
// 模拟工作
sleep(30);
// 解锁
munlock(buf, size);
free(buf);
return 0;
}
编程注意事项:mlock 的位置
- 在分配内存后立即调用
mlock,除非使用mlockall(MCL_FUTURE)。 - 对于匿名映射(如
mmap(MAP_ANONYMOUS)),同样可以使用mlock。 - 避免锁定栈内存:栈会动态增长,难以精确控制,通常使用
mlockall来锁定全部内存更简单。
| 需求 | 方法 |
|---|---|
| 锁定一小块关键数据 | mlock(addr, len) |
| 锁定整个进程内存(包括未来分配) | mlockall(MCL_CURRENT \| MCL_FUTURE) |
| 按需锁定(延迟锁定) | mlockall(MCL_ONFAULT) |
| 解锁 | munlock / munlockall |
重要:锁定内存是特权操作,务必在设计中评估内存使用量,并设置合理的 ulimit 限制,避免系统不稳定。