我正在尝试实现了解动态内存分配是如何发生的。因此,我想使用系统调用实现自己的mallocsbrk()
。 我的问题是当我尝试分配动态内存时,sbrk() 和 malloc() 返回不同的地址不连续。
这是我的代码
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
printf("nsbrk(0) %llu ",(unsigned long long)sbrk(0));
printf("nmalloc(8) %llu ",(unsigned long long)malloc(8));
printf("nmalloc(8) %llu ",(unsigned long long)malloc(8));
printf("nsbrk(8) %llu ",(unsigned long long)sbrk(8));
printf("nmalloc(8) %llu ",(unsigned long long)malloc(8));
printf("nmalloc(8) %llu ",(unsigned long long)malloc(8));
printf("n");
return 0;
}
上述代码的输出为
sbrk(0) 30306304
malloc(8) 30306320
malloc(8) 30306352
sbrk(8) 30441472
malloc(8) 30306384
malloc(8) 30306416
谁能解释为什么sbrk(8)
不是连续的位置。
假设你在Linux上运行,malloc()
和sbrk()
的内存在位置上差异较大的原因是glibcmalloc()
实现在内部使用sbrk()
来获取诸如malloc()
返回给调用方的内存。 例如,假设初始内部 glibc 实现通过sbrk()
获取 32 MB 的堆内存,并且从malloc()
返回的内存将位于这 32 MB 的块中。 如果随后使用sbrk()
获取内存,它将来自原始 32 MB 块末尾新分配的内存,因此来自malloc()
和sbrk()
的地址将有所不同。
请注意,您不能安全地混合使用malloc()
(以及calloc()
、realloc()
等)和sbrk()
,因为malloc()
的内部实现使用sbrk()
来获取它通过malloc()
返回的内存。 根据 Linuxmalloc()
手册页:
通常,
malloc()
从堆中分配内存,并调整 根据需要调整堆的大小,使用sbrk(2)
. 分配区块时 大于MMAP_THRESHOLD
字节的内存,glibcmalloc()
实现将内存分配为专用匿名映射 使用mmap(2)
.MMAP_THRESHOLD
默认为 128 kB,但 使用mallopt(3)
调节。 在 Linux 4.7 分配之前 使用不受RLIMIT_DATA
资源影响的mmap(2)
执行 限制;从 Linux 4.7 开始,此限制也对分配强制执行 使用mmap(2)
执行。
当您在 Linux 上混合malloc()
和sbrk()
以获取内存时,您可能会损坏进程的堆。
该标准不保证存储的连续性,即使是通过连续调用malloc
分配的内存。因此,代码中对malloc
的不同调用不需要产生连续的位置。
C11标准规定:
7.22.3 内存管理功能
1. 通过连续调用
aligned_alloc
、calloc
、malloc
和realloc
函数未指定。
来自malloc
和sbrk
呼叫混合的地址也不必是连续的。