Skip to content

页式和段式内存管理

页式内存管理 (Paging)

页式内存管理是目前最常用、最主流的虚拟内存管理方式。它的核心思想是将程序(逻辑地址空间)和物理内存空间都划分为固定大小的块。

核心概念:

  • 页 (Page): 进程的逻辑地址空间被划分为一系列固定大小的块,称为页。每个页都有一个页号(Page Number)和页内偏移量(Offset)。
  • 页帧 (Frame / Page Frame): 物理内存被划分为与页相同大小的块,称为页帧。每个页帧也有一个帧号。
  • 页表 (Page Table): 操作系统为每个进程维护一个页表。页表记录了进程的每个虚拟页与其在物理内存中的对应页帧的映射关系。页表的每一项通常包含:
    • 页帧号: 指示该虚拟页在物理内存中对应的页帧号。
    • 有效位 (Valid/Invalid Bit): 指示该页是否当前在物理内存中。如果不在,则会触发缺页中断。
    • 修改位 (Dirty Bit): 指示该页在内存中是否被修改过。如果被修改,在置换出去时需要写回磁盘。
    • 访问位 (Accessed Bit): 指示该页近期是否被访问过,用于页置换算法。
    • 保护位: 控制页的读/写/执行权限。

地址转换过程:

当CPU生成一个虚拟地址时,内存管理单元(MMU)会进行以下转换: 1. 解析虚拟地址: 虚拟地址被分成两部分:页号 (P)页内偏移量 (D)。 * 虚拟地址 = (P, D) 2. 查找页表: MMU使用页号P作为索引,在当前进程的页表中查找对应的页表项。 3. 获取物理页帧号: 从页表项中获取到对应的物理页帧号 (F)。 4. 构建物理地址: 将物理页帧号F与页内偏移量D组合起来,形成最终的物理地址。 * 物理地址 = (F, D)

页式内存管理的优点:

  • 消除外部碎片: 由于页和页帧大小固定且可以不连续存放,所以不会产生小的、无法利用的内存碎片(外部碎片)。(但可能会有少量内部碎片,即一个页的最后一个块可能没被完全利用)。
  • 实现虚拟内存: 物理内存不必连续,进程的逻辑地址空间可以远大于物理内存。
  • 内存隔离和保护: 每个进程有独立的页表,可以有效隔离进程内存,防止相互干扰。页表中的保护位可以控制访问权限。
  • 简化内存分配: 操作系统只需要找到一个空闲页帧即可,无需寻找连续的大块内存。
  • 共享代码和数据: 可以通过让不同进程的页表项指向同一个物理页帧来实现代码或数据的共享(例如共享库)。

页式内存管理的缺点:

  • 内部碎片: 由于页大小固定,一个进程的最后一个页可能无法完全填满,导致页内未使用的空间成为内部碎片。
  • 页表过大: 如果虚拟地址空间很大,页表会非常大。例如,64位系统下,页表可能需要多级结构才能管理。
  • 地址转换开销: 每次内存访问都需要查两次内存(一次查页表,一次查实际数据)。虽然TLB(Translation Lookaside Buffer)缓存可以缓解这个问题,但仍然是额外的开销。

段式内存管理 (Segmentation)

段式内存管理试图从程序员的角度来组织内存,它将程序的逻辑地址空间划分为一系列逻辑单元,这些逻辑单元被称为“段”。每个段都有其独立的逻辑意义和大小,例如代码段、数据段、堆栈段等。

核心概念:

  • 段 (Segment): 进程的逻辑地址空间被划分为不定长、具有逻辑意义的段。每个段都有一个段号(Segment Number)和段内偏移量(Offset)。
  • 段表 (Segment Table): 操作系统为每个进程维护一个段表。段表记录了进程的每个逻辑段在物理内存中的起始地址和长度(界限)。段表的每一项通常包含:
    • 基址 (Base Address): 该段在物理内存中的起始地址。
    • 界限 (Limit / Length): 该段的长度。
    • 保护位: 控制段的读/写/执行权限。

地址转换过程:

当CPU生成一个虚拟地址时,MMU会进行以下转换: 1. 解析虚拟地址: 虚拟地址被分成两部分:段号 (S)段内偏移量 (D)。 * 虚拟地址 = (S, D) 2. 查找段表: MMU使用段号S作为索引,在当前进程的段表中查找对应的段表项。 3. 边界检查: 检查段内偏移量D是否小于等于该段的界限值。如果D > 界限,则表示越界访问,会触发硬件异常。 4. 计算物理地址: 如果未越界,则将该段的基址与段内偏移量D相加,得到最终的物理地址。 * 物理地址 = 基址 + D

段式内存管理的优点:

  • 符合程序员逻辑: 以逻辑单元(代码、数据、堆栈)划分,方便程序员进行程序设计和管理。
  • 易于实现共享和保护: 以段为单位进行保护和共享,例如多个进程可以共享同一个代码段。
  • 动态增长: 某些段(如堆栈)可以根据需要动态增长,只需修改段表中的界限值即可。

段式内存管理的缺点:

  • 外部碎片: 由于段的长度不固定,在内存中会产生大小不一的空闲块,这些小块内存可能无法被后续的进程利用,导致外部碎片问题。
  • 内存分配复杂: 操作系统需要寻找大小合适的连续内存块来放置段,这比页式管理更复杂。
  • 地址转换开销: 同样需要查两次内存(一次查段表,一次查实际数据),并且需要进行边界检查。

段页式内存管理 (Segmented Paging)

现代操作系统为了结合两者的优点并规避它们的缺点,常常采用段页式内存管理。它将程序的逻辑地址空间先划分为多个段,每个段再细分为多个页。

核心概念:

  • 段表: 每个进程有一个段表,记录了每个段的基址和长度。这里的“基址”不再是物理地址,而是指向该段对应的“页表”的物理地址(页表基址)。
  • 页表: 每个段都有一个自己的页表。页表记录了该段内部的虚拟页到物理页帧的映射关系。

地址转换过程:

当CPU生成一个虚拟地址时: 1. 解析虚拟地址: 虚拟地址被分成三部分:段号 (S)页号 (P)页内偏移量 (D)。 * 虚拟地址 = (S, P, D) 2. 查找段表: MMU使用段号S查找进程的段表,获取该段对应的页表起始地址和长度。 3. 边界检查: 检查页号P是否在该段的页表范围内(即P < 段长度/页大小)。 4. 查找页表: 根据段表获取的页表起始地址和页号P,找到对应的页表项。 5. 获取物理页帧号: 从页表项中获取物理页帧号 (F)。 6. 构建物理地址: 将物理页帧号F与页内偏移量D组合,得到最终的物理地址。 * 物理地址 = (F, D)

段页式内存管理的优点:

  • 结合优点: 既保留了段式管理按逻辑单元划分的优点(易于共享、保护和动态增长),又利用了页式管理消除外部碎片的优点。因为每个段内部是以页为单位进行分配的,所以段本身无需占据连续的物理内存。
  • 更细粒度的控制: 可以对每个段甚至每个页进行独立的保护和管理。

段页式内存管理的缺点:

  • 地址转换次数增加: 每次内存访问可能需要三次内存访问(一次查段表,一次查页表,一次查实际数据),进一步增加了地址转换的开销。TLB在这里的作用更为关键。
  • 管理复杂: 操作系统需要同时管理段表和多个页表,增加了管理的复杂性。