将内存锁定在物理内存

在大多数操作系统中,操作系统内核负责管理物理内存和虚拟内存。应用程序通常与虚拟内存进行交互,而不是直接与物理内存交互。这意味着,当你在程序中申请内存时(例如,使用C/C++中的mallocnew),你实际上是在申请虚拟内存空间。操作系统负责将这些虚拟内存映射到物理内存上,而且这种映射是动态的,可以发生改变。如果需要,操作系统会将不活跃的内存页交换(swap)到磁盘上。

尽管直接控制物理内存不是通常程序所做的,但在某些特定场景下,如需要确保数据处理的实时性,避免交换带来的延迟,你可能希望申请的内存常驻物理内存。在Linux系统中,可以通过以下几种方式来实现:

1. mlockmlockall

  • mlock函数允许你锁定进程地址空间中的一部分,使其常驻内存,不被交换到磁盘上。
  • mlockall函数可以锁定调用进程的所有映射内存,包括后续映射的内存。

使用这些函数需要相应的权限(通常是超级用户权限),因为它们会影响操作系统的内存管理策略。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main() {
void* buffer = malloc(1024 * 1024 * 1024); // 申请1MB内存
if (buffer == NULL) {
perror("malloc failed");
return 1;
}

// 尝试锁定内存
if (mlock(buffer, 1024 * 1024 * 1024) != 0) {
perror("mlock failed");
free(buffer);
return 1;
}

// 你的代码,使用内存...
int a;
scanf("%d", &a);

// 解锁内存
munlock(buffer, 1024 * 1024 * 1024);
free(buffer);
return 0;
}

2. 使用madvise

  • madvise函数提供了一种机制,告诉内核如何处理申请的内存区域的预期使用模式。虽然madvise并不直接锁定内存,但是它的MADV_WILLNEED标志可以用来建议内核预加载某个区域的数据,这在某种程度上可以减少页面错误和提高访问速度。