9.9.1 malloc 和 free 函数
在使用malloc函数的时候分配的是堆区的空间,但是堆区是虚拟内存啊。怎么知道在物理内存中一定有足够的空间分配呢?
这是一个非常好的问题,它触及了操作系统内存管理的核心。你的理解是正确的,malloc 分配的是虚拟内存,而程序在运行时使用的是虚拟地址空间。
简单直接的答案是:程序(以及malloc)本身不需要知道,也无需担心物理内存是否足够。这是操作系统(内核)的职责,它通过一套复杂的机制来保证这一点。
下面我来详细解释这个过程是如何工作的:
1. 虚拟内存系统的核心:按需分配物理页
操作系统和硬件(MMU,内存管理单元)共同维护着一个从虚拟地址到物理地址的映射表(页表)。当你调用 malloc(1024 * 1024) 申请1MB空间时,会发生以下事情:
- 分配虚拟地址范围:
malloc库函数会在你进程的堆区(一段虚拟地址空间)找到一块连续的、未使用的1MB大小的虚拟地址范围,标记为已分配,然后返回这个范围的起始地址给你。 - 此时并未分配物理内存:在绝大多数情况下,在这一步,操作系统并没有真正分配1MB的物理内存。它只是在你的进程页表中,将这1MB的虚拟地址空间标记为“无效”的映射。这意味着任何试图访问这块新内存的操作,都会触发一个特殊的硬件异常——缺页中断(Page Fault)。
2. 缺页中断:真正分配物理内存的时刻
当你第一次访问刚才 malloc 得到的内存时(比如写入一个数据),CPU 的 MMU 会查找页表,发现这个虚拟地址还没有映射到任何物理内存页(即“缺页”),于是触发一个缺页中断。
操作系统内核的缺页中断处理程序会接管CPU,并执行以下操作:
- 找到一个空闲的物理页帧(Page Frame):内核会从系统的空闲物理页列表中取出一个4KB大小的物理页。
- 更新页表:内核建立这个虚拟页到刚找到的物理页的映射关系,并将页表项标记为“有效”。
- 继续执行程序:中断处理完成后,CPU 回到你的程序刚才那条访问内存的指令重新执行。这次,MMU 就能成功找到物理地址,访问得以继续。
这个过程是“按需分配”的,也称为“延迟分配”。你申请了1MB,但可能只写了前100个字节,那么实际上可能只分配了1个物理页(4KB)给你,而不是一下子分配256个物理页。
3. 操作系统如何保证总有物理内存?——交换(Swapping)
现在回到你的核心问题:如果所有进程都在疯狂申请内存并访问,物理内存终究会不够用的,怎么办?
这时,操作系统的另一个核心机制就登场了:交换(Swapping)。
当物理内存紧张时,操作系统内核的页面置换算法(如LRU,最近最少使用)会开始工作:
- 选出“牺牲”页:算法会找出最近最少使用的一些物理内存页。
- 写入交换空间:如果这个页的内容是从磁盘上的可执行文件映射来的(如代码段),且没有被修改过,直接丢弃即可(需要时再从文件读回来)。如果页的内容被修改过(是“脏”的),内核会将其内容写入到磁盘上专门的交换分区(Swap Partition) 或交换文件(Swap File) 中。
- 释放物理页:将这个物理页标记为空闲,可以分配给新的缺页中断使用。
- 修改页表:将原来映射到这个物理页的进程的页表项标记为“无效”,并记录“这个页的内容现在在磁盘的XX位置”。
当进程之后又访问到那个被换出的页面时,会再次触发缺页中断。这次,操作系统的处理程序会发现这个页不在内存中而在磁盘上,于是会:
- 找到一个空闲的物理页。
- 从磁盘的交换空间中将数据读回这个物理页。
- 更新页表,建立映射。
- 然后让进程继续执行。
通过这种“交换”机制,操作系统将物理内存和磁盘空间结合了起来,使得虚拟内存空间看起来几乎是无限的(64位系统尤其如此)。只要磁盘上的交换空间足够,malloc 就能一直成功返回虚拟地址。
总结
| 步骤 | malloc 的角色 |
操作系统内核的角色 |
|---|---|---|
| 申请内存 | 在进程的虚拟地址空间中划定一块区域,返回起始地址。不涉及物理内存。 | 记录虚拟地址范围已被占用,但页表映射为“无效”。 |
| 使用内存 | 程序对返回的地址进行读写。 | 触发缺页中断。内核分配物理页,建立映射,然后让程序继续。 |
| 内存不足 | 无感知,继续在虚拟地址空间工作。 | 启动交换机制,将不常用的物理页内容写到磁盘,腾出空间给新的缺页中断。 |
所以,你不需要担心物理内存是否足够。你只需要知道:
malloc几乎总是会成功(除非你的虚拟地址空间都用光了,这在32位程序中是可能的,但在64位程序中极难发生)。- 只有在真正使用这些内存时,系统才会背后为你分配物理资源。
- 如果整个系统(物理内存+交换空间)都耗尽了,
malloc会失败返回NULL,或者操作系统会杀死某些进程来释放内存(Linux 中的 OOM Killer)。但这种情况通常意味着系统已经配置不当或负载极重。

浙公网安备 33010602011771号