相关疑难解决方法(0)

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;
}
Run Code Online (Sandbox Code Playgroud)

编译以下代码时:

 printf("%10p\n", sbrk(0));
Run Code Online (Sandbox Code Playgroud)

我收到警告提示:

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

问题1:为什么?


在我之后malloc(1024 * 1024),程序突破似乎没有改变.

这是输出:

9b12000
9b12000
9b12000
Run Code Online (Sandbox Code Playgroud)

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


[更新]摘要:brk()或mmap()

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

mallopt() …

c malloc memory-management mmap sbrk

16
推荐指数
3
解决办法
9634
查看次数

在malloc中,为什么要完全使用brk?为什么不只使用mmap?

malloc使用brk/ sbrk作为从OS声明内存的主要方式的典型实现。但是,它们还用于mmap获取大容量分配的块。使用brk代替确实有真正的好处mmap,还是仅仅是传统?将其与所有内容一起使用mmap是否会很好?

(注意:我在这里可以互换使用sbrkbrk因为它们是同一个Linux系统调用接口brk。)


作为参考,以下是一些描述glibc malloc的文档:

GNU C库参考手册:GNU分配器
https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html

glibc Wiki:Malloc概述
https://sourceware.org/glibc/wiki/MallocInternals

这些文件所描述的是,它sbrk被用来声明一个小的分配的主要场所,mmap被用来声明一个次级的场所,mmap还被用来声明一个大对象(“比页面大得多”)的空间。

同时使用应用程序堆(带有sbrk),并mmap引入了一些其他不必要的复杂性:

分配的竞技场-主竞技场使用应用程序的堆。其他竞技场使用mmap堆。要将块映射到堆,您需要知道哪种情况适用。如果该位为0,则该块来自主区域和主堆。如果该位为1,则该块来自mmap的内存,并且可以从该块的地址计算出堆的位置。

[Glibc malloc源自ptmalloc,而ptmalloc则源自dlmalloc,后者始于1987年。]


jemalloc手册页(http://jemalloc.net/jemalloc.3.html)有这样一段话:

传统上,分配器使用sbrk(2)获取内存,由于一些原因,该内存不是最佳的,原因包括竞争条件,增加的碎片以及人为限制最大可用内存。如果操作系统支持sbrk(2),则此分配器将按优先顺序使用mmap(2)和sbrk(2);否则,此分配器将使用mmap(2)和sbrk(2)。否则,仅使用mmap(2)。

因此,他们甚至在这里说这sbrk不是次优的,但是无论如何他们还是会使用它,即使他们已经为编写代码而烦恼,以至于没有它就可以工作。

[jemalloc的编写始于2005年。]

更新:更多地考虑这一点,关于“按优先顺序”的一点让我对询问保持了一致。为什么选择优先顺序?它们是否只是sbrkmmap不支持(或缺少必要功能)的情况下用作备用,还是该进程可能进入可以使用sbrk但不能使用的状态mmap?我看一下他们的代码,看看是否能弄清楚它在做什么。


我之所以问是因为我正在用C实现垃圾回收系统,到目前为止,我看不到除之外的任何用途mmap。我想知道是否还有什么我想念的。

(就我而言,我还有另一个避免使用的原因brk,那就是malloc在某些时候可能需要使用。)

c linux malloc mmap brk

8
推荐指数
5
解决办法
557
查看次数

malloc()在哪里分配内存?是进程虚拟地址空间的数据段还是堆段?

自从我被介绍到 以来C,我就被告知C动态内存分配是使用家族中的函数完成的malloc。我还了解到,动态分配的内存malloc是在进程的堆部分分配的。

在此输入图像描述

各种操作系统教科书都说这malloc涉及系统调用(虽然并不总是但有时)来将堆上的结构分配给进程。现在假设malloc返回指向堆上分配的字节块的指针,为什么它需要系统调用。函数的激活记录放置在进程的堆栈部分中,并且由于“堆栈部分”已经是进程虚拟地址空间的一部分,所以激活记录的压入和弹出、堆栈指针的操作,只需从虚拟地址空间的最高可能地址。它甚至不需要系统调用。

现在基于同样的理由,由于“堆部分”也是进程虚拟地址空间的一部分,为什么需要系统调用来在该部分中分配字节块。像这样的例程malloc可以自行处理“空闲”列表和“已分配”列表。它需要知道的只是“数据部分”的结尾。某些文本说系统调用对于“将内存附加到进程以进行动态内存分配”是必要的,但是如果malloc在“堆部分”上分配内存,为什么需要在 期间将内存附加到进程malloc?可以简单地取自过程中已经一部分的部分。

在阅读 Kernighan 和 Ritchie 的《C 编程语言》[2e] 文本时,我发现了他们对该malloc函数的实现 [第 8.7 节第 185-189 页]。作者说:

malloc根据需要调用操作系统获取更多内存。

这就是操作系统文本所说的,但与我上面的想法相反(如果malloc在堆上分配空间)。

由于向系统请求内存是一项相对昂贵的操作,因此作者不会在每次调用 时都这样做,因此他们创建了一个至少请求单位的malloc函数;这个较大的块根据需要被切碎。而基本的空闲列表管理是由.morecoreNALLOCfree

但问题是作者使用sbrk()向操作系统请求内存morecore。现在维基百科说:

brk和是 Unix 和类 Unix 操作系统中使用的基本内存管理系统调用,用于控制分配给进程数据段sbrk的内存量。

在哪里

数据段(通常表示为.data)是目标文件或程序的相应地址空间的一部分,其中包含初始化的静态变量,即全局变量和静态局部变量。

我猜这不是“堆部分”。[数据部分是上图中从下数第二部分,而堆是从下数第三部分。]


我完全困惑了。我想知道到底发生了什么以及这两个概念如何正确?请通过将分散的碎片连接在一起来帮助我理解这个概念......

c malloc memory-management heap-memory sbrk

3
推荐指数
1
解决办法
4332
查看次数

标签 统计

c ×3

malloc ×3

memory-management ×2

mmap ×2

sbrk ×2

brk ×1

heap-memory ×1

linux ×1