【操作系统】内存中的分页到底是个啥?它比普通分区好在哪里?

265 阅读5分钟

内存中的分页到底是个啥?它比普通分区好在哪里?

引言:为什么“分内存”这件事那么复杂?

在很多操作系统课程或面试题中,我们常会遇到一个问题:

“请你解释什么是分页?它相比连续分配或分区管理,有什么优势?”

这个问题看似基础,却拷问着你对操作系统内存管理的核心机制理解程度。


一开始,内存分配是“连续”的

在没有分页机制之前,操作系统采用的是连续分配可变分区分配策略。

简单说就是:程序多大,就从物理内存中划一块连续空间给它。

听上去没问题对吧?但现实是:

  • 程序退出后留下的“碎片”没法马上复用
  • 程序越多,内存越容易“碎成渣”
  • 如果某个大程序需要一整块连续空间,即使总内存够,也可能找不到合适的一整块

这就是著名的“外部碎片问题”。

举个例子:

假设你有 8MB 的内存:

  • 程序 A 用了 2MB
  • 程序 B 用了 3MB
  • 程序 C 用了 1MB

A 退出后,这 2MB 空出来,但不是“合并在一起”的,碎片散落。你新来的程序 D 需要 2.5MB,虽然总空闲空间足够,但就是没地方安置。


分页:把“大块”切成“小格”

分页机制的核心思想是:打碎连续的内存分配假设

  • 将物理内存划分成固定大小的页框(Page Frame),比如每个 4KB
  • 将逻辑地址空间也划分成相同大小的页(Page)
  • 程序运行时,不再需要一整块连续空间,只需分配若干离散页即可

操作系统通过**页表(Page Table)**来记录每一页逻辑地址对应的物理内存位置。

类比一下:

与其强行要求“找一块完整的空地造别墅”,不如把程序切成集装箱,每个页框就是码头的空位,哪里有空就放哪里。


分页到底解决了什么?

1. 消除了外部碎片

页是固定大小的,页与页之间没有缝隙,物理地址不必连续,所以再也不用担心“碎片太多但拼不出一块完整空间”的尴尬。

2. 程序逻辑地址和物理地址彻底解耦

这点非常重要:

程序以为自己在一个完整的大地址空间里运行,实际上它的每一页可能分布在内存的任何位置。

这给了操作系统巨大的自由度,比如:

  • 进程隔离(页表隔离不同进程地址空间)
  • 内存共享(多个进程映射相同页)
  • 延迟加载(按需加载某些页)
  • 虚拟内存机制(页不在内存就换到磁盘)

这直接催生了现代 OS 的核心机制:虚拟内存 + 页式管理


❖ 分页 vs 分区管理:核心对比

维度分区管理(连续分配)分页管理
地址连续性要求物理地址连续物理地址可不连续
外部碎片明显几乎没有
内部碎片不定(分区大小不一)存在(最后一页可能用不满)
管理复杂度相对简单页表较复杂,需要 MMU 支持
灵活性高(支持虚拟内存、共享、保护等)

简单总结:

  • 分区管理适合资源少的小系统
  • 分页管理适合多进程、大程序、高并发的现代操作系统

程序员视角下,分页机制的真实意义

你可能会问:我作为开发者,真的需要关心分页吗?

答案是:需要,但是间接的。

举例:

  • 你在 C++ 中访问数组越界,有可能“刚好”访问了另一个页,操作系统会因为页权限触发 Segmentation Fault。
  • 操作系统的fork()能高效复制进程,靠的是写时复制(Copy-on-write) ,也基于分页机制。
  • 内存映射文件(如mmap)利用分页机制将磁盘文件映射为页。
  • 页式分配也是现代 malloc/new 背后的核心机制之一。

所以,理解分页不是为了写代码,而是为了理解系统如何“帮你跑代码”。


延伸:分页的进化版本——多级页表与TLB

分页也不是完美的:

  • 每个程序一个页表,页数多了就会占用大量内存(尤其是 32 位/64 位地址空间下)
  • 每次内存访问都要查页表,很慢

于是出现了:

  • 多级页表(树状结构,节省空间)
  • 快表(TLB) :高速缓存常用的页表项,极大提高访问效率

现代 CPU 的 MMU(内存管理单元)+ TLB + 多级页表,是分页系统的“三件套”。


分页不是分块,它比简单分区高级多了~

分页的本质,不是简单的“把内存切成格子”,而是建立一种逻辑地址到物理地址的灵活映射机制。它不仅解决了内存碎片问题,更支持了虚拟内存、进程隔离、共享内存、异常处理等现代操作系统最核心的能力。

分页机制不是面向你写的代码的,而是操作系统为你跑这些代码而建造的系统基础设施。

感谢大家的阅读!如果觉得写得还不错的话欢迎多多点赞收藏!你们的支持是我更新最大动力!