brk()、sbrk()和realloc()函数的区别

8

据我所知,函数brk()和sbrk()用于重新分配内存。但它们与realloc()函数有何不同?请给出编码示例。


2
(s)brk函数是遗留函数,并且已经从POSIX标准中删除。据我所知,它们也从未成为C标准的一部分。 - Elias Van Ootegem
不仅如此,除非你是malloc的实现者,否则调用带有非零参数的sbrk或根本不调用brk都是不安全的。在malloc背后移动内存断点将破坏内部数据结构,并导致程序在下一次使用mallocreallocfree时崩溃——几乎所有的C库函数都允许在内部使用malloc - zwol
2个回答

9

brksbrk是系统调用(在内核中实现),而mallocfreerealloc是用户空间库函数。因此,malloc等函数在内部使用brksbrk,但提供了额外的功能(有关brk的更多详细信息,请参见man(2),有关malloc的更多详细信息,请参见man(3))。

brk仅告诉内核程序想要使用多少内存,通过给内核一个指向程序可能使用的最大虚拟内存位置的指针。但你只有一个大块内存。

malloc帮助你将这个巨大的内存块细分为较小的部分。

示例代码在这里没有太多意义,因为brkmalloc在不同的层面上工作。但你可以考虑如何实现一个非常简单(且不线程安全)的mallocfree版本,以及在哪里使用brk

  1. 我们原始malloc的基本数据结构是一个链表。
  2. 列表中的每个列表元素包含:
    1. 块的大小
    2. 指向下一个元素的指针
    3. 一个标志,表示块是否正在使用
    4. 一个标志,表示它是否是最后一个元素
    5. 给定大小的字节数组
  3. 在每次调用中,malloc遍历列表并检查每个块
    1. 如果块被标记为“未使用”
    2. 如果列表元素的大小字段最多与所需大小一样大
  4. 如果malloc找到这样的块,则会:
    1. 将列表元素标记为已使用
    2. 调整列表元素中的大小字段
    3. 如果有足够的空间,则在元素之后添加一个列表元素,指向列表中的下一个元素(如果适用)
    4. 返回它找到的列表元素的字节数组的指针
  5. 如果malloc没有找到这样的列表元素,则会
    1. 调用brk以增加我们从内核获得的可用内存
    2. 在列表末尾添加一个新元素,将大小设置为所需大小
    3. 将此元素标记为正在使用和最后一个元素
    4. 返回新创建的列表条目的字节数组的指针

正如@BasileStarynkevitch在他的评论中所指出的那样,作为brk的替代方案,您还可以使用mmap(使用fd=-1flags=MAP_PRIVATE|MAP_ANONYMOUS)来保留由交换文件支持的单个内存块。有关mmap的详细信息,请参见man(2)


实际上,现在大多数好的malloc实现都使用mmap(2)sbrkbrk往往会变得过时(并且不适合线程)。 - Basile Starynkevitch

7
在操作系统级别上(至少在Unix模型中),程序有一个大的内存区域,用于存放程序文本、初始化和未初始化的数据以及“堆”(用于动态分配数据)。 (栈是单独的。)您可以使用brksbrk调整该区域的大小,但无法重新排列它,并且它始终是连续的。大多数进行动态内存分配的程序都需要更灵活的东西。 mallocfreerealloc是C库函数,它们提供了更加灵活的功能。在底层,它们通过调用brk和/或sbrk从操作系统获取内存,但然后它们进行额外的处理,让您可以(a)分配任意数量的(b)不同大小的块,您可以(c)在完成后单独将它们返回到池中,顺便(d)调整大小。
但是,当您使用free将内存返回到池中时,它通常只会回到未来由您的程序调用malloc的池中;内存通常不会被返还给操作系统。
(抱歉没有提供任何示例代码;我现在没有时间。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接