malloc() 是如何在内部实现的?[复制]

How is malloc() implemented internally? [duplicate]

提问人:bodacydo 提问时间:8/14/2010 最后编辑:orlpbodacydo 更新时间:9/21/2020 访问量:166539

问:

谁能解释一下内部是如何工作的?malloc()

我有时这样做,我看到很多系统调用,谈论它被用于,但仅此而已。strace programsbrkman sbrkmalloc()

C 内存 malloc 系统调用 sbrk

评论

2赞 msw 8/14/2010
使用来源 Boda Cydo。ftp.gnu.org/gnu/glibc
0赞 Rishabh 8/14/2010
我认为此链接在某种程度上回答了您的问题 stackoverflow.com/questions/1119134/how-malloc-and-free-work

答:

126赞 DarkDust 8/14/2010 #1

系统调用移动数据段的“边界”。这意味着它移动了程序可以读取/写入数据的区域的边界(让它增长或缩小,尽管AFAIK没有真正使用该方法将内存段返回内核)。除此之外,还有用于将文件映射到内存,但也用于分配内存(如果您需要分配共享内存,那就是您的方式)。sbrkmallocmmapmmap

因此,您有两种方法可以从内核获取更多内存:和 .关于如何组织从内核获得的内存,有多种策略。sbrkmmap

一种幼稚的方法是将其划分为多个区域,通常称为“桶”,这些区域专用于某些结构大小。例如,实现可以为 16、64、256 和 1024 字节结构创建存储桶。如果您要求为您提供给定大小的内存,它会将该数字四舍五入到下一个存储桶大小,然后从该存储桶中为您提供一个元素。如果需要,可以使用更大的区域直接与内核进行分配。如果一定大小的存储桶是空的,则可以为新存储桶获得更多空间。mallocmallocmallocmmapmallocsbrk

有各种各样的设计,可能没有一种真正的实现方式,因为您需要在速度、开销和避免碎片化/空间效率之间做出妥协。例如,如果存储桶的元素用完了,则实现可能会从更大的存储桶中获取元素,将其拆分并将其添加到元素用完的存储桶中。这将非常节省空间,但并非每个设计都可行。如果您只是通过 / 获得另一个桶,那可能会更快、更容易,但不会节省空间。此外,设计当然必须考虑到“免费”需要以某种方式再次提供空间。您不会只分发内存而不重复使用内存。mallocmallocsbrkmmapmalloc

如果您有兴趣,OpenSER/Kamailio SIP 代理有两种实现(它们需要自己的实现,因为它们大量使用共享内存,并且系统不支持共享内存)。请参见:https://github.com/OpenSIPS/opensips/tree/master/memmallocmalloc

然后你也可以看看 GNU libc malloc 实现,但那个非常复杂,IIRC。

评论

12赞 Gab是好人 4/30/2017
IIRC = 如果我没记错的话
64赞 doron 8/14/2010 #2

简单地说,像这样工作:mallocfree

malloc提供对进程堆的访问。堆是 C 核心库(通常是 libc)中的一种构造,它允许对象获得对进程堆上某些空间的独占访问权限。

堆上的每个分配都称为堆单元。这通常由一个标头组成,该标头包含有关单元大小的信息,以及指向下一个堆单元的指针。这使得堆实际上成为链表。

当启动一个进程时,堆包含一个单元,其中包含启动时分配的所有堆空间。此单元格存在于堆的可用列表中。

当调用 时,将从大型堆单元中获取内存,该堆单元由 返回。其余部分形成一个新的堆单元,该堆单元由内存的所有其他部分组成。mallocmalloc

当释放内存时,堆单元将添加到堆的可用列表的末尾。随后在自由列表中寻找合适大小的单元格。malloc

可以预料,堆可能会碎片化,堆管理器可能会不时尝试合并相邻的堆单元。

当可用列表中没有剩余内存用于所需分配时,调用或系统调用从操作系统请求更多内存页。mallocbrksbrk

现在,有一些修改可以优化堆操作。

  • 对于大型内存分配 (通常> 512 字节,堆 管理器可以直接进入操作系统,然后 分配一个完整的内存页。
  • 堆 可以指定最小大小 分配以防止大量资金 的碎片化。
  • 堆还可以将自身划分为多个箱,一个用于小分配,一个用于较大的分配,以更快地进行较大的分配。
  • 还有一些巧妙的机制可以优化多线程堆分配。
9赞 mgalgs 9/17/2013 #3

同样重要的是要认识到,简单地移动程序中断指针,实际上并没有分配内存,它只是设置了地址空间。例如,在 Linux 上,当访问该地址范围时,内存将由实际的物理页“备份”,这将导致页面错误,并最终导致内核调用页面分配器以获取备份页。brksbrk

评论

1赞 Marco van de Voort 2/8/2019
根据操作系统的不同,它可以充当增加空页面保留的信号,以便在请求到来时可以快速完成。这确实会导致内存使用量增加。但是,首先,您的陈述是正确的。