一、总览:从 malloc 到真正的内存
当你在 C 程序中写下:
void *p = malloc(1024);
这一行表面上是在“申请 1KB 内存”,
但本质上,这只是向操作系统登记了 1KB 虚拟地址空间,
并没有真正分配物理内存。
真正的物理内存分配,要等到程序第一次访问这块虚拟地址时才发生。
二、阶段一:用户态调用 malloc
1. malloc() 的行为
- malloc 向操作系统申请 虚拟内存空间,
通常通过brk()或mmap()完成。 - 内核只在进程的虚拟地址空间中标记:“这块地址可用”,
并在页表中标注“尚未分配物理页”。
此时的状态:
虚拟内存:✔ 已分配
物理内存:❌ 还没有
页表映射:❌ 尚未建立
类比:
你向房东预订了一间房(malloc),但还没真正入住,
房东只在名册上写下“这间房给你留着”。
三、阶段二:第一次访问内存 → 触发缺页中断
当程序第一次读或写这块内存时(例如 *p = 1;):
- CPU 查页表,发现该虚拟页没有对应的物理页(
P=0); - 于是触发 Page Fault(缺页中断);
- 进程从 用户态切换到内核态,
内核的 Page Fault Handler(缺页中断处理函数)接管控制。
四、阶段三:缺页中断处理流程
缺页中断处理函数负责让虚拟页真正“落地”成物理页:
- 检查内存是否有空闲页
-
- 若有:直接分配;
- 若无:启动内存回收机制。
- 分配物理页并建立映射
-
- 分配一页物理内存;
- 更新页表,将该虚拟页映射到物理页;
- 设置访问权限(可读/可写/用户态)。
- 恢复用户态执行
-
- 进程回到用户态;
- 重新执行刚才那条导致缺页的指令。
此时:
虚拟内存:✔ 已分配
物理内存:✔ 已分配
页表映射:✔ 已建立
类比:
你终于去酒店前台登记入住(缺页中断),
前台分配了真正的房间钥匙(物理页),
并在系统中建立“房号–住客”的对应表(页表)。
五、阶段四:内核回收机制(当内存不够时)
如果系统找不到空闲物理页,内核就要“挤一挤”:
1. 后台回收(kswapd)
- 内核线程
kswapd异步运行; - 当系统检测到内存紧张时被唤醒;
- 回收不常用的页(LRU 策略),写回磁盘(Swap),释放物理页;
- 异步进行,不阻塞进程。
2. 直接回收(direct reclaim)
- 当进程申请内存速度太快,后台跟不上;
- 当前进程会被阻塞,等待内核同步释放页;
- 这是“紧急”同步回收机制。
3. 仍然不够:触发 OOM(Out Of Memory)
- 如果两种回收方式都无法腾出空间;
- 内核启动 OOM Killer(内存溢出杀手);
- 选择内存占用大的进程并强制杀死,以释放资源;
- 若仍不足,会持续杀进程,直到系统恢复。
优先级规则(简化):
- 内存占用高;
- 权重低(非系统关键进程);
- 用户态程序优先被杀。
六、阶段五:总结整个路径
1️⃣ 程序申请
→ malloc() 调用 → 虚拟地址空间扩大
(通过 brk/mmap,尚未映射物理页)
2️⃣ 程序访问
→ CPU 查页表 → 发现页不存在 → 缺页中断
→ 进入内核态
3️⃣ 内核分配
→ 分配物理页 → 更新页表 → 返回用户态
4️⃣ 程序继续执行
→ 虚拟地址与物理地址正式对应,读写正常
七、内存分配过程简图
用户空间 (User Space)
┌──────────────────────────────┐
│ malloc() │
│ ↓ │
│ 分配虚拟内存 (未映射) │
│ ↓ │
│ 第一次访问 → 缺页中断 │
│ ↓ │
│ 内核分配物理页 + 建立映射 │
│ ↓ │
│ 用户继续执行 │
└──────────────────────────────┘
│
▼
内核空间 (Kernel Space)
┌──────────────────────────────┐
│ Page Fault Handler │
│ ├─ 查找空闲页 │
│ ├─ 无页 → kswapd 回收 │
│ ├─ 再无页 → OOM Killer │
│ └─ 更新页表映射 │
└──────────────────────────────┘
八、形象类比总结
|
阶段 |
技术行为 |
生活类比 |
|
malloc() |
申请虚拟内存 |
预定房间 |
|
第一次访问 |
缺页中断 |
你到前台登记入住 |
|
Page Fault Handler |
分配物理页 |
前台分配房间并登记 |
|
kswapd |
后台清理旧房 |
清理空房间以供入住 |
|
direct reclaim |
你等清洁工打扫完才能入住 |
同步等待 |
|
OOM Killer |
房间爆满时赶走住客 |
强制清理占用者 |
九、一句话总结
malloc 分配的是虚拟内存,不是物理内存;
第一次访问才触发缺页中断,由内核分配物理页并建立映射;
若内存紧张,内核通过 kswapd → direct reclaim → OOM Killer 三层机制逐步回收。
完整路径:

6785

被折叠的 条评论
为什么被折叠?



