第五章:内存管理

5.1 内存管理的基本概念

内存管理是OS对内存空间的分配和回收。好比图书馆的阅览室管理员——不同的读者(进程)需要不同的区域(内存空间),管理员要合理分配座位,还要记录谁占了哪儿。

5.1.1 逻辑地址与物理地址

地址类型 定义 来源
逻辑地址(虚拟地址) CPU生成的地址 编译后的程序
物理地址 内存单元的真实地址 地址转换后

地址转换:程序中的逻辑地址 → OS/硬件转换为物理地址。

5.1.2 程序的装入和链接

链接方式:

  1. 静态链接:在程序运行前将所有目标模块链接成一个完整的可执行文件。
  2. 装入时动态链接:装入内存时边装入边链接。
  3. 运行时动态链接:运行时需要某模块时才链接(节省内存,常用)。

装入方式:

  1. 绝对装入:程序中的地址就是物理地址(只适合单道程序环境)。
  2. 可重定位装入:装入时一次性将逻辑地址转换为物理地址(静态重定位)。
  3. 动态运行时装入:运行时每访问一次地址就转换一次(动态重定位,需要MMU硬件支持——现代OS标准)。

💡 记忆技巧:三种装入方式的区别在于"什么时候转换地址"——绝对装入(编译时)、可重定位装入(装入时)、动态运行时装入(运行时)。

5.2 连续分配管理方式

5.2.1 单一连续分配

内存分为系统区和用户区,用户区一次只给一道程序用。早期单道批处理使用。简单但浪费严重。

5.2.2 固定分区分配

内存划分为固定大小的区域,每个分区可装一道作业。分为分区大小相等和分区大小不等。

  • 优点:实现简单。
  • 缺点:分区内碎片(内部碎片——分区没装满的部分),分区数量固定,多道程度受限。

5.2.3 动态分区分配

不再预分固定区域,而是根据进程需求动态划分。随着进程的创建和终止,内存会产生外部碎片(各分区之间的空隙)。

解决外部碎片:紧凑技术(移动进程内容,使其连续排列)——代价高(需要动态重定位支持)。

📌 408考点提示:内部碎片(固定分区有)vs 外部碎片(动态分区有)是常见选择题。

5.3 动态分区分配算法

算法 策略 优点 缺点
首次适应(FF) 从低地址开始找第一个满足的分区 简单、速度快 低地址留下小碎片
最佳适应(BF) 找到满足要求的最小分区 保留大分区 产生很多小碎片
最坏适应(WF) 找到最大的分区 减少小碎片产生 大分区很快被切小
邻近适应(NF) 从上次分配位置继续找 不用每次从头扫描 高地址也产生碎片

📌 408考点提示:四种算法的对比选择题常见。首次适应(FF)是实际系统中使用最广泛的算法。

5.4 非连续分配管理方式

5.4.1 基本分页存储管理

基本思想:把逻辑地址空间分成大小相等的页(Page),物理内存分成同样大小的页框/页帧(Page Frame),通过页表实现映射。

页表:记录逻辑页号→物理页框号的映射关系。每个进程有自己的页表。

地址转换过程:

  1. 逻辑地址 = 页号 + 页内偏移
  2. 查页表:页号 → 页框号
  3. 物理地址 = 页框号 × 页大小 + 页内偏移

计算示例:

  • 逻辑地址32位,页大小4KB(2^12)→ 页号20位,页内偏移12位
  • 页表项4字节 → 页表大小 = 2^20 × 4B = 4MB

快表(TLB——Translation Lookaside Buffer):

  • 页表在内存中,每次访问内存都要查页表(多一次内存访问)。
  • TLB是CPU中的高速缓存(类似Cache),存储最近使用的页表项。
  • 引入TLB后:先在TLB中查找 → 找到(TLB命中)直接转换;找不到再到内存查页表。

有效访问时间(EAT)计算:

  • 设TLB命中率 = a,TLB访问时间 = t,内存访问时间 = m
  • TLB命中时:t + m(查TLB + 访问内存)
  • TLB未命中时:t + 2m(查TLB + 查页表 + 访问内存——实际上查页表也需要一次内存访问)
  • EAT = a × (t + m) + (1-a) × (t + 2m) = t + m + (1-a) × m

5.4.2 基本分段存储管理

基本思想:程序按逻辑分段(如主程序段、数据段、栈段),每段有自己的名字和长度。

段表:记录段号→基址+段长。

地址转换:逻辑地址(段号+段内地址)→ 查段表 → 基址+段内地址 → 物理地址。

分段vs分页:

对比 分页 分段
目的 提高内存利用率(消除外部碎片) 满足编程逻辑(模块化)
大小 固定(由OS决定) 可变(由程序决定)
地址空间 一维(线性地址) 二维(段号+段内地址)
用户可见性 用户不可见 用户可见(编程时考虑分段)
共享 较难 容易(按段共享)

5.4.3 段页式管理

结合了分页和分段:先分段,每段内再分页。

  • 逻辑地址 = 段号 + 段内页号 + 页内偏移
  • 需要段表(段号→页表地址)和页表(页号→页框号)
  • 地址转换:段表→页表→物理地址(三次内存访问,但TLB可以加速)

5.5 虚拟内存

5.5.1 局部性原理

虚拟内存的理论基础是局部性原理:

  • 时间局部性:刚访问过的地址很可能再次被访问(循环)。
  • 空间局部性:刚访问过的地址附近的地址很可能被访问(顺序执行)。

5.5.2 虚拟内存的概念

虚拟内存:将程序的一部分装入内存,其余部分放在磁盘上。程序可以使用比物理内存更大的地址空间。

实现方式:

  • 请求分页存储管理
  • 请求分段存储管理
  • 请求段页式存储管理

虚拟内存的特征:

  • 多次性:作业分多次调入内存。
  • 对换性:作业可以在内存和磁盘间对换。
  • 虚拟性:逻辑上扩充内存容量。

5.5.3 请求分页管理方式

页表机制:在基本分页页表的基础上增加状态位(是否在内存)、访问字段(记录访问次数/时间)、修改位(是否被修改)、外存地址。

缺页中断:当访问的页不在内存时,CPU触发缺页中断——从磁盘将页调入内存。缺页中断属于内中断/异常中的故障(fault)。

地址变换过程:

  1. 访问逻辑地址,解析页号+偏移。
  2. 查TLB:命中→得到页框号→拼成物理地址→访问数据。
  3. TLB未命中:查内存中的页表——如果该页在内存中,更新TLB,访问数据。
  4. 如果该页不在内存中:触发缺页中断→从磁盘调入→更新页表和TLB→重执行指令。

📌 408考点提示:请求分页的地址转换过程(含TLB和缺页中断处理)是综合题的常见素材。

5.5.4 页面置换算法

当内存已满而需要调入新页时,必须置换某个页面。

算法 策略 是否可能产生Belady异常 评价
OPT(最佳置换) 置换未来最长时间不再访问的页 否 理论最优,无法实现
FIFO(先进先出) 置换最先进入内存的页 是 简单但性能差
LRU(最近最久未使用) 置换最长时间未使用的页 否 性能好,但需硬件支持
CLOCK(NRU——最近未使用) 扫描页的访问位,第一轮找0,第二轮清0重找 否 近似LRU,常用

⚠️ 易错点:

  • FIFO的Belady异常:分配的页面增多,缺页率反而上升。只有FIFO有此问题。
  • LRU需要硬件计数器或栈支持,实现成本高。
  • CLOCK算法(NRU) 是LRU的近似实现——给每个页一个访问位,循环扫描。

缺页率计算:缺页次数 / 总访问次数。

💡 记忆技巧:OPT=预知未来(不能实现),FIFO=先进先出(像排队),LRU=看过去(最久没用过),CLOCK=转圈检查(像钟表扫描)。

5.6 页面分配策略

5.6.1 分配策略

策略 物理块数量 置换范围
固定分配局部置换 固定 只能置换自己的页
可变分配全局置换 可变 可从全局空闲中取
可变分配局部置换 可变(可增减) 只能置换自己的页

5.6.2 工作集与抖动

  • 工作集:进程在一段时间内频繁访问的页面集合。
  • 抖动(颠簸):分配给进程的物理块太少,导致频繁缺页——CPU忙于换页,利用率急剧下降。

解决方法:采用工作集模型——确保分配给进程的物理块数 ≥ 工作集大小。

5.7 内存映射文件

内存映射文件(Memory-Mapped File):将磁盘文件映射到虚拟地址空间的一个区域。访问该区域就像访问内存一样——由OS在背后自动处理换页。

优点:统一了文件访问和内存访问;多个进程可以共享同一映射。

示例题

示例1(地址转换):页面大小为4KB,某页表内容如下。逻辑地址为:0x2A3C,求物理地址。

假定页表:页号0→页框号3, 页号1→页框号7, 页号2→页框号1, 页号3→页框号5

解:页面大小4KB=2^12,所以页内偏移占12位。 0x2A3C = 0010 1010 0011 1100(二进制) 高20位(这里简化为高4位示意)为页号=2(0x2),低12位为页内偏移=0xA3C 查页表:页号2→页框号1 物理地址 = 1 × 4096 + 0xA3C = 4096 + 2620 = 0x1A3C 实际物理地址 = 0x1000 + 0xA3C = 0x1A3C

示例2(页面置换——LRU):页面访问序列:7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,分配3个页框。求LRU的缺页次数。

解(手动模拟):

步 访问 页框1 页框2 页框3 是否缺页
1 7 7 - - 缺
2 0 7 0 - 缺
3 1 7 0 1 缺
4 2 2 0 1 缺(替换7——最久未用)
5 0 2 0 1 已存在,不换
6 3 2 0 3 缺(替换1——最久未用)
7 0 2 0 3 已存在
8 4 4 0 3 缺(替换2——最久未用)
9 2 4 0 2 缺(替换3)
10 3 4 3 2 缺(替换0——最久未用)
11 0 0 3 2 缺(替换4)
12 3 0 3 2 已存在
13 2 0 3 2 已存在
14 1 0 1 2 缺(替换3——最久未用)
15 2 0 1 2 已存在

缺页次数:10次。缺页率 = 10/15 ≈ 66.7%

示例3(有效访问时间计算):TLB命中率98%,TLB访问时间10ns,内存访问时间100ns。求有效访问时间(假设TLB未命中时访问页表需一次内存访问)。

解:EAT = 0.98 × (10 + 100) + 0.02 × (10 + 100 + 100) = 0.98 × 110 + 0.02 × 210 = 107.8 + 4.2 = 112 ns

对比无TLB的情况:每次访问需查页表(100ns)+ 访问数据(100ns)= 200ns,TLB使性能提升了约44%。

本章小结

内存管理是操作系统的核心功能之一。重点掌握:逻辑地址到物理地址的转换(分页/分段/段页式)、连续分配算法的对比、页面置换算法的缺页率计算(OPT/FIFO/LRU/CLOCK)、虚拟内存的概念和工作原理。地址转换计算和缺页率模拟是408的常见考题,需要多练习。