内存中分页(Paging)和分段(Segmentation)的区别是什么?
内存管理中的分页(Paging)和分段(Segmentation)都是为了实现非连续内存分配的技术,允许程序分散地存储在物理内存中。
它们的主要区别在于划分内存的依据和看待内存的视角不同。
以下是核心区别的详细对比:
1. 核心区别总结表
| 特性 | 分页 (Paging) | 分段 (Segmentation) |
|---|---|---|
| 划分依据 | 物理划分(按固定大小) | 逻辑划分(按功能模块) |
| 单位大小 | 固定(如 4KB) | 可变(取决于代码/数据长度) |
| 目的 | 提高内存利用率,解决外部碎片 | 方便编程、信息共享和保护 |
| 可见性 | 对用户/程序员不可见(系统行为) | 对用户/程序员可见(逻辑结构) |
| 地址空间 | 一维(单一线性地址) | 二维(段号 + 段内偏移) |
| 碎片类型 | 产生内部碎片(最后一页未填满) | 产生外部碎片(段与段之间的空隙) |
| 共享与保护 | 较难(因为一页内可能混杂不同类型数据) | 容易(以逻辑单位为基础,如代码段只读) |
2. 详细原理解析
1. 划分单位与大小 (Unit & Size)
- 分页: 操作系统将逻辑地址空间切分成固定大小的块,称为页(Page);将物理内存切分成同样大小的块,称为页框(Page Frame)。大小由硬件决定(通常是 4KB)。
- 分段: 按照程序的逻辑结构划分。例如,主函数是一个段,子程序是一个段,堆栈是一个段,数据是一个段。段的大小不固定,由程序内容的长度决定。
2. 目的与视角 (Purpose & Perspective)
- 分页: 是出于系统管理的需求。也就是为了让操作系统能更有效地利用物理内存,只要有空闲的页框就能分配,不需要连续的大块内存。这对程序员是透明的(你感觉不到它的存在)。
- 分段: 是出于用户/程序员的需求。它反映了程序的逻辑结构。程序员知道“这是我的代码段”,“这是我的数据段”。
3. 地址空间 (Address Space)
- 分页: 地址空间是一维的。程序员只需要给出一个线性地址(例如
0x00F0),硬件的内存管理单元(MMU)会自动将其拆分为“页号”和“页内偏移”。 - 分段: 地址空间是二维的。CPU 寻址时需要提供两个值:段名(段号) 和 段内偏移量。
4. 碎片问题 (Fragmentation)
- 分页:
- 无外部碎片: 内存被切成整齐的小块,任何空闲页框都能被利用。
- 有内部碎片: 进程的最后一页通常装不满(例如页大小 4KB,程序只需 4.1KB,则需要 2 个页,第 2 页浪费了 3.9KB)。
- 分段:
- 无内部碎片: 段的大小正好是程序所需的大小。
- 有外部碎片: 因为段的大小不固定,随着段的换入换出,内存中会留下许多不连续的小空隙,这些空隙太小而无法容纳新的段。
5. 共享与保护 (Sharing & Protection)
- 分页: 共享和保护比较麻烦。因为一个页面是物理切割的,它可能前半部分是代码(只读),后半部分是数据(可写)。你很难对这一页设置统一的权限。
- 分段: 非常容易。因为一个段就是一个完整的逻辑单元(比如整个代码库)。你可以轻松地将“代码段”标记为只读,或将“共享库段”共享给其他进程。
3. 现代操作系统的做法:段页式管理 (Paged Segmentation)
在现代操作系统(如 Linux, Windows)和硬件(如 x86 架构)中,通常结合了两者的优点,采用段页式存储管理:
- 先将用户程序分成若干个逻辑段(利用分段的逻辑优势,便于共享保护)。
- 再把每个段分成若干个固定大小的页(利用分页的物理优势,解决外部碎片)。
简单来说: 分段是给程序员看的逻辑结构,分页是给硬件看的物理实现。