我正在尝试了解动态内存分配是如何发生的。因此,我想到了使用sbrk()
系统调用来实现自己的malloc。
我的问题是当我尝试分配动态内存时,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)
不是连续的位置。
答案 0 :(得分:1)
该标准不能保证连续调用malloc
所分配的存储 的连续性。因此,在代码中对malloc
的不同调用无需产生连续的位置。
C11标准规定:
7.22.3 Memory management functions
1.由连续调用分配给存储区的顺序和连续性 未指定
aligned_alloc
,calloc
,malloc
和realloc
函数。
并且malloc
和sbrk
调用混合产生的地址也不必是连续的。
答案 1 :(得分:0)
假设您正在Linux上运行,则malloc()
和sbrk()
的内存在位置上有较大差异的原因是glibc malloc()
实现使用了sbrk()
在内部获取诸如malloc()
之类的功能的内存返回给调用方。例如,假设初始内部glibc实现通过sbrk()
获得32 MB的堆内存,并且从malloc()
返回的内存将位于这32 MB块中。如果然后使用sbrk()
获取内存,则它将来自原始32 MB块末尾新分配的内存,因此malloc()
和sbrk()
的地址将有所不同。
请注意,由于{{1}的内部实现,您不能安全地混合使用malloc()
(和calloc()
,realloc()
等)和sbrk()
}使用malloc()
获取通过sbrk()
返回的内存。根据{{3}}:
通常,
malloc()
从堆中分配内存,并调整 使用malloc()
根据需要调整堆大小。分配块时 大于sbrk(2)
个字节的内存,glibcMMAP_THRESHOLD
实现将内存分配为私有匿名映射 使用malloc()
。mmap(2)
默认为128 kB,但 可使用MMAP_THRESHOLD
进行调整。在Linux 4.7之前的分配 使用mallopt(3)
执行的操作不受mmap(2)
资源的影响 限制;从Linux 4.7开始,此限制也适用于分配 使用RLIMIT_DATA
执行。
在Linux上混合使用mmap(2)
和malloc()
以获得内存时,很可能会破坏进程的堆。