为什么 malloc() 会导致轻微的页面错误?
Why does malloc() cause minor page fault?
我想了解内存和页面错误,所以我写了下面的代码来检查我的理解。我不明白为什么调用 malloc 会导致 MINFL 增加,因为 malloc() 不应该影响物理内存(据我所知)。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
void main() {
printf("Before malloc\n");
getchar();
malloc(1 << 20);
printf("After malloc\n");
getchar();
}
这些是 ps 命令的最终结果。
在 malloc 之前:
malloc 之后:
有两点我不明白:
- 为什么 MINFL 会增加?
- 为什么 VSZ 增加了 1028 而不是 1024?
请帮忙,谢谢。
两个的答案是一样的,确实很简单。
如您所知,Glibc malloc
将使用 mmap
直接分配大于 128 KiB 的块。但是,它将需要在指针下方 写入簿记信息 - 因为如果只给一个指针,free
还怎么知道它应该做什么。如果打印 malloc
返回的指针,您将看到它 未 页对齐。
这是一个演示所有这些的程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#define ALLOCATION_SIZE (1 << 20)
int main(void) {
struct rusage usage = {0};
getrusage(RUSAGE_SELF, &usage);
printf("1st before malloc: %lu\n", usage.ru_minflt);
getrusage(RUSAGE_SELF, &usage);
printf("2nd before malloc: %lu\n", usage.ru_minflt);
char *p = malloc(ALLOCATION_SIZE);
printf("pointer returned from malloc: %p\n", p);
getrusage(RUSAGE_SELF, &usage);
printf("after malloc: %lu\n", usage.ru_minflt);
p[0] = 42;
getrusage(RUSAGE_SELF, &usage);
printf("after writing to the beginning of the allocation: %lu\n", usage.ru_minflt);
for (size_t i = 0; i < ALLOCATION_SIZE; i++) {
p[i] = 42;
}
getrusage(RUSAGE_SELF, &usage);
printf("after writing to every byte of the allocation: %lu\n", usage.ru_minflt);
}
输出类似于
1st before malloc: 108
2nd before malloc: 118
pointer returned from malloc: 0x7fbcb32aa010
after malloc: 119
after writing to the beginning of the allocation: 119
after writing to every byte of the allocation: 375
即getrusage
和 printf
第一次导致页面错误,所以我们调用它两次 - 现在错误计数在 malloc
调用之前是 118,在 malloc
之后是 119 . 如果你看一下指针,0x010 不是 0x000 即分配不是页面对齐的 - 前 16 个字节包含 free
的簿记信息,因此它知道它需要使用 munmap
来释放内存块,以及分配块的大小!
现在这自然就解释了为什么大小增加是 1028 Ki 而不是 1024 Ki - 必须保留一个额外的页面 以便有足够的 space那16个字节!它还解释了页面错误的来源——因为 malloc
必须将簿记信息写入写时复制归零页面。这可以通过写入分配的第一个字节来证明——它不再导致页面错误。
最后,for 循环将修改页面并触及 257 映射中剩余的 256 页。
如果您将 ALLOCATION_SIZE
更改为 ((1 << 20) - 16)
,即只分配少 16 个字节,您会发现虚拟大小和页面错误数都与值 你在期待。
我想了解内存和页面错误,所以我写了下面的代码来检查我的理解。我不明白为什么调用 malloc 会导致 MINFL 增加,因为 malloc() 不应该影响物理内存(据我所知)。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
void main() {
printf("Before malloc\n");
getchar();
malloc(1 << 20);
printf("After malloc\n");
getchar();
}
这些是 ps 命令的最终结果。
在 malloc 之前:
malloc 之后:
有两点我不明白:
- 为什么 MINFL 会增加?
- 为什么 VSZ 增加了 1028 而不是 1024?
请帮忙,谢谢。
两个的答案是一样的,确实很简单。
如您所知,Glibc malloc
将使用 mmap
直接分配大于 128 KiB 的块。但是,它将需要在指针下方 写入簿记信息 - 因为如果只给一个指针,free
还怎么知道它应该做什么。如果打印 malloc
返回的指针,您将看到它 未 页对齐。
这是一个演示所有这些的程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#define ALLOCATION_SIZE (1 << 20)
int main(void) {
struct rusage usage = {0};
getrusage(RUSAGE_SELF, &usage);
printf("1st before malloc: %lu\n", usage.ru_minflt);
getrusage(RUSAGE_SELF, &usage);
printf("2nd before malloc: %lu\n", usage.ru_minflt);
char *p = malloc(ALLOCATION_SIZE);
printf("pointer returned from malloc: %p\n", p);
getrusage(RUSAGE_SELF, &usage);
printf("after malloc: %lu\n", usage.ru_minflt);
p[0] = 42;
getrusage(RUSAGE_SELF, &usage);
printf("after writing to the beginning of the allocation: %lu\n", usage.ru_minflt);
for (size_t i = 0; i < ALLOCATION_SIZE; i++) {
p[i] = 42;
}
getrusage(RUSAGE_SELF, &usage);
printf("after writing to every byte of the allocation: %lu\n", usage.ru_minflt);
}
输出类似于
1st before malloc: 108
2nd before malloc: 118
pointer returned from malloc: 0x7fbcb32aa010
after malloc: 119
after writing to the beginning of the allocation: 119
after writing to every byte of the allocation: 375
即getrusage
和 printf
第一次导致页面错误,所以我们调用它两次 - 现在错误计数在 malloc
调用之前是 118,在 malloc
之后是 119 . 如果你看一下指针,0x010 不是 0x000 即分配不是页面对齐的 - 前 16 个字节包含 free
的簿记信息,因此它知道它需要使用 munmap
来释放内存块,以及分配块的大小!
现在这自然就解释了为什么大小增加是 1028 Ki 而不是 1024 Ki - 必须保留一个额外的页面 以便有足够的 space那16个字节!它还解释了页面错误的来源——因为 malloc
必须将簿记信息写入写时复制归零页面。这可以通过写入分配的第一个字节来证明——它不再导致页面错误。
最后,for 循环将修改页面并触及 257 映射中剩余的 256 页。
如果您将 ALLOCATION_SIZE
更改为 ((1 << 20) - 16)
,即只分配少 16 个字节,您会发现虚拟大小和页面错误数都与值 你在期待。