在执行malloc时内核会发生什么?

62
在面试中,我被问到了这个问题。他们想知道当用户调用malloc(4)来分配4字节的内存时,操作系统(Linux)会如何响应?哪个子系统会响应此系统调用?
我告诉他,malloc()将由内存管理子系统提供服务。malloc()实现将通过空闲内存(物理内存)列表查找适当的大于或等于4字节的块。一旦找到这样的块,它将从空闲列表中删除并添加到一个已使用列表中。然后,该物理内存将映射到进程堆vma结构中。但是,他好像对这个答案不太满意。伙伴系统如何与此相匹配?任何帮助都将不胜感激。

8
他当时很生气。malloc()是在用户模式下实现的。 - Chris Becke
3
@Chris:大部分情况下,malloc可能会调用sbrk。 - Tom Anderson
6
@Chris:不一定。这里给出的答案暗示了 malloc() 从物理内存中分配,这有点错误。 - JeremyP
此外,“操作系统”并不等同于“内核”;我认为,在谈论Unix时,“操作系统”可以理解为“内核、引导程序、libc以及基本的用户模式程序,如init、getty、login和其他相关程序”。根据面试官提问的具体方式,谈论分配器在用户模式下的作用可能是一个合理的答案。 - Tom Anderson
他可能对你在用户调用malloc和内核函数malloc之间混淆不满意。你所描述的应该是内核malloc的功能。 - CCNA
跨操作系统版本:https://dev59.com/eXNA5IYBdhLWcg3wBpHs - Ciro Santilli OurBigBook.com
2个回答

87

当用户空间应用程序调用malloc()时,该调用并未在内核中实现。相反,它是一个库调用(由glibc或类似的库实现)。

简而言之,glibc中的malloc实现要么从brk()/sbrk()系统调用中获取内存,要么通过mmap()获取匿名内存。这使得glibc拥有大量连续的(关于虚拟内存地址的)内存块,malloc实现进一步将其切成较小的块并分配给您的应用程序。

这里有一个小的malloc实现,可以让您了解这个过程,以及许多其他链接。

请注意,目前还没有关注物理内存 - 当进程数据段通过brk()/sbrk()mmap()进行更改,并且在引用内存时(通过读取或写入内存)由内核虚拟内存系统处理。

总结:

  1. malloc()将搜索其托管的内存片段,查看是否有未使用的内存片段符合分配要求。
  2. 如果失败,则malloc()将尝试扩展进程数据段(通过sbrk()/brk()或在某些情况下mmap())。sbrk()最终进入内核。
  3. 内核中的brk()/sbrk()调用将调整进程的struct mm_struct中的一些偏移量,因此进程数据段将变得更大。首先,没有物理内存映射到扩展数据段所给出的附加虚拟地址。
  4. 当该未映射内存第一次被触摸时(可能是malloc实现的读/写),将启动故障处理程序并陷入内核,内核将向未映射内存分配物理内存。

3
请问您能否详细说明第四点是如何实现的?我只想知道物理内存最终是如何分配的,以及内核代码的哪一部分负责此操作? 谢谢。 - Arjun Bora
1
@ArjunBora 不好意思,那是一个相当大的话题。请另外提出一个问题。 - nos

17

malloc并不直接处理物理内存,它处理分页虚拟内存 - 尽管我不确定是否适用于所有体系结构。

当程序尝试分配内存且空闲列表中没有相等或更大尺寸的块时,将分配一个全新的页面。页面大小取决于体系结构(在x86上为4096字节)。页分配是只有内核可以执行的操作,因此malloc调用可能会导致系统调用。然后,新地址被添加到空闲列表中,malloc根据其实现方式操作空闲列表(例如检查glibc)。


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