操作系统中的内存管理:内存分配算法(非连续内存分配)详解
字数 1604 2025-11-25 19:54:55
操作系统中的内存管理:内存分配算法(非连续内存分配)详解
1. 问题描述
在连续内存分配中,进程需要一块连续的物理内存空间,可能导致内存碎片问题(外部碎片)。非连续内存分配允许进程的内存空间分散在物理内存的不同位置,从而更灵活地利用内存。核心问题是如何管理这些分散的内存块,并实现高效的地址转换。
2. 非连续内存分配的基本思想
- 进程视角:进程的地址空间被划分为多个逻辑单元(如段或页),每个单元可以独立分配到物理内存的不同区域。
- 硬件支持:需要地址转换机制(如段表、页表)将逻辑地址映射到物理地址。
- 优势:减少外部碎片,提高内存利用率;允许部分加载进程(如分页机制下仅加载常用页)。
3. 实现方式一:分页(Paging)
步骤1:逻辑地址划分
- 将进程的地址空间划分为固定大小的单元,称为页(Page)(如4KB)。
- 物理内存同样划分为与页大小相同的页框(Page Frame)。
步骤2:页表的作用
- 操作系统为每个进程维护一个页表(Page Table),记录每个页号到页框号的映射。
- 逻辑地址结构:
页号P + 页内偏移d。
步骤3:地址转换过程
- CPU访问逻辑地址,由内存管理单元(MMU)自动拆分出页号
P和偏移d。 - 查询页表,找到页号
P对应的页框号F。 - 物理地址 =
F × 页大小 + d。
示例:
- 页大小4KB,逻辑地址0x2001(二进制:0010 0000 0000 0001)。
- 页号P=2(高4位),偏移d=1(低12位)。
- 若页表显示页号2映射到页框5,则物理地址 =
5×4096 + 1 = 0x5001。
步骤4:页表的优化问题
- 页表可能过大(如32位系统需2^20个表项),需通过多级页表或倒排页表减少空间开销。
4. 实现方式二:分段(Segmentation)
步骤1:按逻辑单元划分
- 进程地址空间按功能划分为多个段(Segment)(如代码段、数据段、堆栈段),每段长度可变。
步骤2:段表的作用
- 段表(Segment Table)记录每个段的基地址(物理内存起始地址)和段长(边界检查用)。
- 逻辑地址结构:
段号S + 段内偏移d。
步骤3:地址转换过程
- 根据段号
S查找段表,获取基地址base和段长limit。 - 检查偏移
d是否合法(d < limit),若越界则触发异常。 - 物理地址 =
base + d。
示例:
- 逻辑地址:段号2,偏移0x100。
- 段表显示段2的基地址为0x5000,段长0x200。
- 物理地址 =
0x5000 + 0x100 = 0x5100。
步骤4:段的优势与挑战
- 优势:符合程序逻辑结构,便于共享和保护(如代码段只读)。
- 挑战:可能产生外部碎片(需通过内存压缩解决)。
5. 段页式结合(Segmentation with Paging)
步骤1:先分段,再分页
- 逻辑地址:
段号S + 段内页号P + 页内偏移d。 - 先通过段表找到该段的页表基地址,再通过页表找到页框号。
步骤2:地址转换流程
- 根据段号
S查找段表,得到该段对应的页表起始地址。 - 根据页号
P在页表中找到页框号F。 - 物理地址 =
F × 页大小 + d。
优势:结合分段逻辑性与分页内存管理效率,常见于x86架构。
6. 关键问题与解决
- 地址转换速度:通过TLB(快表)缓存常用页表项,减少内存访问次数。
- 内存保护:页表或段表中添加权限位(如读/写/执行权限),防止非法访问。
- 碎片问题:分页机制无外部碎片,但可能有内部碎片(最后一页未用满);分段需处理外部碎片。
总结
非连续内存分配通过分页、分段或段页结合,解决了连续分配的内存碎片问题。核心在于通过硬件辅助的地址转换机制(页表/段表)实现逻辑地址到物理地址的映射,同时需权衡管理开销与效率。