malloc() 使用 brk() 还是 mmap()?

Does malloc() use brk() or mmap()?

c代码:

// program break mechanism
// TLPI exercise 7-1

#include <stdio.h>
#include <stdlib.h>

void program_break_test() {
    printf("%10p\n", sbrk(0));

    char *bl = malloc(1024 * 1024);
    printf("%x\n", sbrk(0));

    free(bl);
    printf("%x\n", sbrk(0));

}

int main(int argc, char **argv) {
    program_break_test();
    return 0;
}

编译以下代码时:

 printf("%10p\n", sbrk(0));

我收到警告提示:

format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’

问题 1:这是为什么?


而我malloc(1024 * 1024)之后,程序中断似乎没有改变。

这是输出:

9b12000
9b12000
9b12000

问题2:进程是否在启动时在堆上分配内存以备将来使用?还是编译器改变了分配的时间点?否则,为什么?


[更新] 总结:brk() 或 mmap()

在查看了 TLPI 并查看手册页(在 TLPI 作者的帮助下)之后,现在我明白了 malloc() 是如何决定使用 brk()mmap() 的,如下所示:

mallopt()可以设置参数来控制malloc()的行为,还有一个参数叫M_MMAP_THRESHOLD,一般来说:

参数的默认值是128kb(在我的系统上),但在我的测试程序中我使用了1Mb,所以选择了mmap(),当我将请求的内存更改为32kb时,我看到 brk() 将被使用。

这本书在TLPI第147页和1035页提到过,但我没有仔细阅读那部分。

参数的详细信息可以在 mallopt() 的手册页中找到。

malloc不限于使用sbrk分配内存。例如,它可能使用 mmap 来映射一个大的 MAP_ANONYMOUS 内存块;通常 mmap 会分配一个远离数据段的虚拟地址。

还有其他的可能性。特别是,malloc,作为标准库的核心部分,本身并不局限于标准库函数;它可以使用特定于操作系统的接口。

如果我们更改程序以查看 malloc 的内存位置:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void program_break_test() {
  printf("%10p\n", sbrk(0));

  char *bl = malloc(1024 * 1024);
  printf("%10p\n", sbrk(0));
  printf("malloc'd at: %10p\n", bl);

  free(bl);
  printf("%10p\n", sbrk(0));

}

int main(int argc, char **argv) {
  program_break_test();
  return 0;
}

sbrk 不会改变或许更清楚。 malloc 给我们的记忆被映射到一个完全不同的位置。

您还可以在 Linux 上使用 strace 查看进行了哪些系统调用,并找出 malloc 正在使用 mmap 执行分配。

如果你在代码中使用malloc,它会在开始时调用brk(),从堆中分配0x21000字节,这是你打印的地址,所以问题1:以下malloc的要求可以从预先分配的space中得到满足,所以这些mallocs实际上并没有调用brk,这是对malloc的优化。如果下次您想 malloc 大小超出该边界,将调用一个新的 brk(如果不大于 mmap 阈值)。