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
,一般来说:
- 如果请求的内存小于它,将使用
brk()
;
- 如果请求的内存大于或等于它,将使用
mmap()
;
参数的默认值是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
阈值)。
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
,一般来说:
- 如果请求的内存小于它,将使用
brk()
; - 如果请求的内存大于或等于它,将使用
mmap()
;
参数的默认值是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
阈值)。