2

我试图实现了解动态内存分配是如何发生的。所以我想到了使用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)不是连续的位置。

4

2 回答 2

3

假设你在 Linux 上运行,内存 frommalloc()sbrk()位置差异较大的原因是 glibcmalloc()实现在sbrk()内部使用来获取内存,例如malloc()返回给调用者。例如,假设最初的内部 glibc 实现通过获取 32 MB 的堆内存,sbrk()并且从中返回的内存malloc()将在这 32 MB 块中。如果您然后使用sbrk()来获取内存,它将来自原始 32 MB 块末尾新分配的内存,因此地址 frommalloc()sbrk()将不同。

请注意,您不能安全地混合使用malloc()(and calloc(), realloc(), etc),sbrk()因为内部实现malloc()使用sbrk()来获取它通过malloc(). 根据Linuxmalloc()手册页

通常,malloc()从堆中分配内存,并根据需要调整堆的大小,使用sbrk(2). 当分配大于MMAP_THRESHOLD字节的内存块时,glibcmalloc() 实现将内存分配为私有匿名映射,使用mmap(2). MMAP_THRESHOLD默认为 128 kB,但可使用mallopt(3). 在 Linux 4.7 之前,使用执行mmap(2)的分配不受RLIMIT_DATA资源限制的影响;自 Linux 4.7 起,此限制也适用于使用mmap(2).

当您在 Linux 上混合malloc()sbrk()获取内存时,您可能会破坏进程的堆。

于 2019-05-22T09:22:12.227 回答
2

即使连续调用malloc. 因此,代码中的不同调用malloc不需要产生连续的位置。

C11 标准规定:

7.22.3 内存管理功能

1.连续调用 、 、 和 函数分配的存储顺序和 aligned_alloc连续性callocmalloc指定realloc

malloc并且来自混和sbrk调用的地址也不必是连续的。

于 2019-05-22T08:08:47.557 回答