为什么 malloc() 可以互换调用 mmap() 和 brk()?

amj*_*jad 15 c linux heap-memory linux-kernel dynamic-memory-allocation

我是 C 和堆内存的新手,仍在努力理解动态内存分配。

我跟踪了Linux系统调用,发现如果我malloc用来请求少量的堆内存,那么内部malloc调用brk

但是如果我使用malloc请求非常大量的堆内存,则在内部malloc调用mmap

所以必须有一个很大的区别brkmmap,但理论上我们应该能够使用brk分配堆内存无论请求的大小。那么为什么在分配大量内存时会malloc调用mmap呢?

ryy*_*ker 7

那么为什么 malloc 在分配大内存时调用 mmap 呢?

简短的回答是为了提高Linux 的较新实现的效率,以及随之而来的更新的内存分配算法。但请记住,这是一个非常依赖于实现的主题,对于所讨论的特定 Linux 操作系统的不同年份和风格,其原因和原因会有很大差异。

这是关于Linux 内存分配中的低级部分mmap()brk()播放的最新文章。并且,一篇不是最近但仍然相关的Linux Journal文章,其中包含一些非常适合此处主题的内容,包括:

对于非常大的请求,malloc() 使用 mmap() 系统调用来查找可寻址内存空间。当大内存块被释放但被较小的、最近分配的块锁定时,这个过程有助于减少内存碎片的负面影响,这些块位于它们和分配空间的末尾之间。在这种情况下,实际上,如果块是用 brk() 分配的,即使进程释放了它,系统也将无法使用它。
(强调我的)

关于brk()
顺便说一句,“... mmap() 在 Unix 的早期版本中不存在。brk()是当时增加进程数据段大小的唯一方法。带有 mmap() 的 Unix 的第一个版本是 80 年代中期的 SunOS,第一个开源版本是 1990 年的 BSD-Reno。 ”。从那时起,内存分配算法的现代实现已经通过许多改进进行了重构,大大减少了它们使用brk().


zwo*_*wol 5

mmap(与 一起使用时MAP_ANONYMOUS)分配一块 RAM,该块可以放置在进程的虚拟地址空间内的任何位置,并且可以在以后(与munmap)独立于所有其他分配进行释放。

brk更改虚拟地址空间的单个连续“arena”的结束地址:如果该地址增加,则会为 arena 分配更多内存,如果减少,则在 arena 末尾释放内存。因此,分配的内存brk只能在进程不再需要arena 末尾的连续地址范围时才能释放回操作系统。

使用brk了较小的分配,以及mmap对大分配,是基于这样的假设是较小的分配更有可能都具有相同的寿命,而大的分配更可能有不与任何其他分配相关的寿命启发式寿命。所以,大分配使用系统原语,让它们独立于其他任何东西被释放,而小分配使用没有的原语。

这种启发式方法不是很可靠。malloc如果我没记错的话,当前一代的实现已经完全放弃brkmmap用于一切。malloc我怀疑您正在查看的实现(GNU C 库中的实现,基于您的标签)非常旧,并且主要继续使用,因为没有人有足够的勇气冒险将其换成可能会更新的东西但不一定更好。

  • `brk` 与 `mmap` 与生命周期无关。只是如果分配大小不受限制,任何可能的“brk”实现的碎片都可能变得任意糟糕(不同的策略有不同的最坏情况)。仅当分配足够大以证明一次给予整个页面时才使用“mmap”。`brk` 并没有被“删除”,只是被有效地内联并变得更加复杂。 (2认同)