Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么malloc()交替调用mmap()和brk()?_C_Linux_Linux Kernel_Heap_Dynamic Memory Allocation - Fatal编程技术网

为什么malloc()交替调用mmap()和brk()?

为什么malloc()交替调用mmap()和brk()?,c,linux,linux-kernel,heap,dynamic-memory-allocation,C,Linux,Linux Kernel,Heap,Dynamic Memory Allocation,我不熟悉C和堆内存,仍在努力理解动态内存分配 我跟踪了Linux系统调用,发现如果我使用malloc请求少量堆内存,那么malloc会在内部调用brk 但是如果我使用malloc请求大量堆内存,那么malloc在内部调用mmap 因此,brk和mmap之间肯定有很大的区别,但理论上我们应该能够使用brk来分配堆内存,而不管请求的大小如何。那么,在分配大量内存时,为什么malloc调用mmap?mmap(与MAP\u ANONYMOUS一起使用时)会分配一块RAM,该RAM可以放在进程虚拟地址空间

我不熟悉C和堆内存,仍在努力理解动态内存分配

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

但是如果我使用
malloc
请求大量堆内存,那么
malloc
在内部调用
mmap

因此,
brk
mmap
之间肯定有很大的区别,但理论上我们应该能够使用
brk
来分配堆内存,而不管请求的大小如何。那么,在分配大量内存时,为什么
malloc
调用
mmap

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

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

对于小分配使用
brk
,对于大分配使用
mmap
是一种启发式方法,其假设是小分配更有可能具有相同的寿命,而大分配更有可能具有与任何其他分配的寿命无关的寿命。因此,大的分配使用系统原语,允许它们独立于其他任何东西进行释放,而小的分配使用原语,而不是

这种启发式方法不太可靠。如果我没记错的话,当前一代的
malloc
实现已经完全放弃了
brk
,而是将
mmap
用于一切。我怀疑您正在查看的
malloc
实现(GNUC库中的一个,基于您的标记)非常旧,主要是因为没有人敢冒险将它换成更新的东西,而更新的东西可能会更好,但不一定会更好。那么,为什么malloc在分配大容量内存时调用mmap呢

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

关于底层部分
mmap()
brk()
在Linux内存分配中发挥作用。这是一篇不太新但仍然相关的文章,其中包含一些与本主题非常相关的内容,包括:

对于非常大的请求,malloc()使用mmap()系统调用来查找 可寻址内存空间。这个过程有助于减少负面影响 释放大内存块时内存碎片的影响 但被更小的、最近分配的块锁定 它们和分配的空间的末尾。事实上,在这种情况下 如果已使用brk()分配该块,则该块仍将不可用 即使进程释放了它,也由系统执行。
(强调矿山)

关于
brk()

“…mmap()在早期版本的Unix中不存在。
brk()
是当时增加进程数据段大小的唯一方法。使用mmap()的Unix的第一个版本是80年代中期的SunOS,第一个开源版本是1990年的BSD Reno。”。从那时起,内存分配算法的现代实现经过了许多改进,大大减少了对它们的需要,包括使用
brk()

brk()
是UNIX中分配内存的一种传统方式,它只是将数据区域扩展了给定的数量
mmap()
允许您分配独立的内存区域,而不限于单个连续的虚拟地址空间块

malloc()
将数据空间用于“小”分配,将
mmap()
用于“大”分配,原因有很多,包括减少内存碎片。这只是一个您不必担心的实现细节


请检查一下。我想强调另一个观点

malloc是分配内存的系统函数

您实际上不需要调试它,因为在某些实现中,它可能会从静态“竞技场”(例如静态字符数组)中为您提供内存

在其他一些实现中,它可能只返回空指针

如果你想了解锦葵的真正用途,我建议你看看

Linux gcc malloc就是基于此

你也可以看看jemalloc。它基本上使用相同的brk和mmap,但数据组织方式不同,通常“更好”


愉快的研究。

减少碎片通常被认为是
mmap
用于大型分配的原因;有关详细信息,请参阅。但我认为这不是现在真正的好处;实际上,即使使用
mmap
,在更大的池(虚拟地址空间,而不是堆)中仍然存在碎片

mmap
的最大优点是可丢弃性

当使用
sbrk
分配内存时,如果实际使用了内存(以便内核在某个点映射物理内存),然后释放了内存,内核本身就无法知道这一点,除非分配器也减少了程序中断(它会