为什么 malloc() 会导致小页面错误?

问题描述

我正在尝试了解内存和页面错误,所以我编写了下面的代码来检查我的理解。我不明白为什么调用 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命令的终端结果。

有两件事我不明白:

  1. 为什么 MINFL 会增加?
  2. 为什么 VSZ 增加了 1028 而不是 1024?

请帮忙,谢谢。

解决方法

答案很简单。 Glibc malloc 将使用 mmap 直接分配大于 128 KiB 的块。但是,它需要在指针下方写簿记信息——因为如果只给出一个指针,free 怎么会知道它应该做什么。如果你打印指针,你会发现它没有页面对齐:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>

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(1 << 20);
    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 < (1 << 20); 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

getrusageprintf 第一次导致页面错误,所以我们调用它两次 - 现在计数是 118;在 malloc 之后,计数为 119。如果您查看指针,0x010 不是 0x000,即分配不是页对齐的 - 前 16 个字节包含 free 的簿记信息,以便它知道它需要使用 munmap 来释放内存块,以及它的大小。

现在这自然解释了为什么大小增加是 1028 Ki 而不是 1024 Ki - 必须保留一个额外的页面,以便有足够的空间容纳这 16 个字节!它还解释了页面错误的来源 - 因为 malloc 必须将簿记信息写入写入时复制归零的页面。这可以通过写入分配的第一个字节来证明 - 它不再导致页面错误。

最后,for 循环将修改页面并触及映射到的 257 个页面中剩余的 256 个页面。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...