操作系统中的内存管理:内存分配算法(非连续内存分配)详解
字数 1604 2025-11-25 19:54:55

操作系统中的内存管理:内存分配算法(非连续内存分配)详解

1. 问题描述
在连续内存分配中,进程需要一块连续的物理内存空间,可能导致内存碎片问题(外部碎片)。非连续内存分配允许进程的内存空间分散在物理内存的不同位置,从而更灵活地利用内存。核心问题是如何管理这些分散的内存块,并实现高效的地址转换。


2. 非连续内存分配的基本思想

  • 进程视角:进程的地址空间被划分为多个逻辑单元(如段或页),每个单元可以独立分配到物理内存的不同区域。
  • 硬件支持:需要地址转换机制(如段表、页表)将逻辑地址映射到物理地址。
  • 优势:减少外部碎片,提高内存利用率;允许部分加载进程(如分页机制下仅加载常用页)。

3. 实现方式一:分页(Paging)
步骤1:逻辑地址划分

  • 将进程的地址空间划分为固定大小的单元,称为页(Page)(如4KB)。
  • 物理内存同样划分为与页大小相同的页框(Page Frame)

步骤2:页表的作用

  • 操作系统为每个进程维护一个页表(Page Table),记录每个页号到页框号的映射。
  • 逻辑地址结构:页号P + 页内偏移d

步骤3:地址转换过程

  1. CPU访问逻辑地址,由内存管理单元(MMU)自动拆分出页号P和偏移d
  2. 查询页表,找到页号P对应的页框号F
  3. 物理地址 = 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:地址转换过程

  1. 根据段号S查找段表,获取基地址base和段长limit
  2. 检查偏移d是否合法(d < limit),若越界则触发异常。
  3. 物理地址 = base + d

示例

  • 逻辑地址:段号2,偏移0x100。
  • 段表显示段2的基地址为0x5000,段长0x200。
  • 物理地址 = 0x5000 + 0x100 = 0x5100

步骤4:段的优势与挑战

  • 优势:符合程序逻辑结构,便于共享和保护(如代码段只读)。
  • 挑战:可能产生外部碎片(需通过内存压缩解决)。

5. 段页式结合(Segmentation with Paging)
步骤1:先分段,再分页

  • 逻辑地址:段号S + 段内页号P + 页内偏移d
  • 先通过段表找到该段的页表基地址,再通过页表找到页框号。

步骤2:地址转换流程

  1. 根据段号S查找段表,得到该段对应的页表起始地址。
  2. 根据页号P在页表中找到页框号F
  3. 物理地址 = F × 页大小 + d

优势:结合分段逻辑性与分页内存管理效率,常见于x86架构。


6. 关键问题与解决

  • 地址转换速度:通过TLB(快表)缓存常用页表项,减少内存访问次数。
  • 内存保护:页表或段表中添加权限位(如读/写/执行权限),防止非法访问。
  • 碎片问题:分页机制无外部碎片,但可能有内部碎片(最后一页未用满);分段需处理外部碎片。

总结
非连续内存分配通过分页、分段或段页结合,解决了连续分配的内存碎片问题。核心在于通过硬件辅助的地址转换机制(页表/段表)实现逻辑地址到物理地址的映射,同时需权衡管理开销与效率。

操作系统中的内存管理:内存分配算法(非连续内存分配)详解 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(快表)缓存常用页表项,减少内存访问次数。 内存保护 :页表或段表中添加权限位(如读/写/执行权限),防止非法访问。 碎片问题 :分页机制无外部碎片,但可能有内部碎片(最后一页未用满);分段需处理外部碎片。 总结 非连续内存分配通过分页、分段或段页结合,解决了连续分配的内存碎片问题。核心在于通过硬件辅助的地址转换机制(页表/段表)实现逻辑地址到物理地址的映射,同时需权衡管理开销与效率。