Skip to content
Self-Knowing

第三章:内存管理

约 2830 个字 预计阅读时间 9 分钟

内存管理概念

在现代操作系统中,程序在被执行前,其代码和数据必须先被加载到内存中。然后,操作系统为程序创建一个进程,这个进程为程序的执行提供了所需的资源和环境。

指令和数据绑定到内存地址可以在三个不同的阶段发生

编译时期(Compile time):在这个阶段,如果编译器已经知道程序将在内存中的具体位置,它可以生成绝对代码,即直接引用物理内存地址的指令。

装入时期(Load time):如果在编译时不知道程序将在内存中的确切位置,编译器会生成可重定位代码。一旦装载,程序就不能移动到内存中的其他位置。

执行时期(Execution time):在最灵活的方案中,程序的地址绑定是在执行时进行的。这种技术需要特殊的硬件支持,如基址(Base)寄存器和限长(Limit)寄存器,来动态地将逻辑地址转换为物理地址。

虚拟内存的空间大小,有两个条件决定

  1. 内存容量和外存容量之和
  2. 地址总线的位数

进程的内存映像

  • 栈:用于存放函数调用的局部变量,函数参数等
  • 堆:用于动态内存分配(malloc/free
  • 数据段:全局变量和静态变量
  • 程序代码区:程序的执行代码
  • 系统内核区(kernel

内存空间的扩充:覆盖技术

思想:常用的放在「固定区」,不常用的放在「覆盖区」(需要时调用,不用时调出)

覆盖是在同一个进程中的。

内存空间的扩充:交换技术

思想:中级调度(挂起)。

交换是在不同进程之间的。

分区分配管理

单一连续分配

  • 内存中只能有一道用户程序
  • 有内部碎片,无外部碎片

固定分区分配

  • 将用户区划分为若干个固定大小的分区
  • 每个分区只装入一道作业
  • 「分区说明表」:记录分区的地址,大小和分配状态
  • 产生内部碎片

提前划分分区大小,都会产生内部碎片 内部碎片:分配个某进程的内存区域中,如果有些部分没有用上

外部碎片:内存中的某些空闲分区由于太小而难以利用

动态分区分配

  • 空闲分区表/空闲分区链
  • 动态分区分配算法:按照要求的算法,找到第一个能满足大小的空闲分区。
    1. 首次适应算法:每次都从低地址开始查找
    2. 最佳适应算法:按容量递增次序
    3. 最坏适应算法:按容量递减次序
    4. 邻近适应算法:每次都从上次查找结束的位置检索
    5. 算法优缺点
  • 回收后合并相邻的空闲分区
  • 有外部碎片
  • 可以通过「紧凑」来解决外部碎片

分页存储管理

页面(页):「虚拟内存」中的一个固定大小的区块。虚拟页面

页框(page frame):「物理内存」中的一个固定大小的区块。物理页框

操作系统负责将「虚拟地址」(由页面和页面内偏移组成)映射到「物理地址」(由页框号和页框内偏移组成)

页表:维护了虚拟页面到物理页框的映射关系。

物理内存大小为 4GB,页面大小为 4KB,则每个页表项至少应该为多少字节? 页框大小 == 页面大小 = 4KB,所以物理页框数为 \(4 GB / 4 KB = 2^{20}\) 页框号需要用 20 bit 来表示,所以需要 3 字节。

页面转换过程

页号 = 逻辑地址 / 页面大小

页内偏移量 = 逻辑地址 % 页面大小

看页面大小有多少,将逻辑地址分为两块,一部分表示页号,另一部分表示页内偏移量。

  1. 根据「逻辑地址」计算出页号、页内偏移量
  2. 判断页号是否越界「越界中断」
  3. 查询页表,找到页框号
  4. 用页框号和页内偏移量得到「物理地址」
  5. 访问目标单元

基于快表的地址变换机构

快表(TLB,translation lookaside buffer),又称「联想寄存器」,是一种高速缓存(Cache),用于存储 最近使用的 虚拟地址到物理地址的映射信息。

先看快表,快表未命中时,再去查找页表

快表

快表命中,只需要一次访存;快表未命中,需要两次访存。

二级页表

页表项的数目 = \(\frac{页面大小}{页表项的大小}\)

页目录表(映射到下一级页表) --> 页表(映射到物理页框) --> 物理页框

分段存储管理

按照程序自身的逻辑关系划分为若干段。

段表中的段表项:「段号」、「段长」和「基址」(段在内存中的起始位置)

分段的地址空间时二维的,既要段名,也要段内地址。

分段、分页管理的对比

  • 页:信息的物理单位,为了实现离散分配,对用户不可见。
  • 段:信息的逻辑单位,为了更好的满足用户需求,对用户时可见的。
  • 分段更容易实现信息的「共享和保护」
  • 分段和分页访问一个逻辑地址都需要「两次访存」,加入快表,命中时可以减少一次。
  • 分段产生「外部碎片」,分页产生「内部碎片」

段页式管理

先分段,段内分页

逻辑地址:段号、页号、页内偏移量

  • 段号的位数:可以分多几个段
  • 页号的位数:每个段有多少页
  • 页内偏移量的位数:页面大小

段页式管理中的「段表」和段式管理中的段表不一样。

段表中对应的段表项对应页表位置:「段号」、「页表长度」、「页表存放块号」

地址访问逻辑:

  1. 访问段表,用「逻辑地址的段号」在段表中找到对应的段表项 --> 确定页表的物理页框号
  2. 用物理页框号 访问页表,用「逻辑地址的页号」在页表中找到对应的页表项 --> 确定物理地址的页框号
  3. 利用物理地址的页框号 + 「逻辑地址的页内偏移量」得到物理地址
  4. 访问物理地址

一共需要三次访存。

虚拟内存管理

虚拟内存:程序不需全部装入即可运行,运行时根据需要动态调入数据,若内存不够,还需换出一些数据。

离散性:在内存分配时采用离散的分配方式,是虚拟存储器的最基本的特征

特征:多次性,对换性,虚拟性。

原理:局部性原理

只有运行的部分程序在内存中。

逻辑地址空间比实际物理地址空间大。

请求分页管理

为了实现虚拟存储器的功能:在分页的基础上增加了 请求掉页,页面置换功能

页表:页号,页框号,状态位,访问字段,修改位,外存地址

  • 状态位:是否调入内存
  • 访问字段:由置换算法决定
  • 修改位:调入内存后是否被修改
  • 外存地址:页面在外存中的地址

地址转换流程:

  1. 访问页表:找到页框号和页内偏移量
  2. 缺页中断:如果页框号对应的页框不在内存中,发生缺页中断
    • 掉入内存,更新页表。
  3. 置换算法:若内存已满,需要从内存中移除一个页面
    • 最佳置换算法(OPT,Optimal)
    • 先进先出(FIFO)
    • 最近最少使用(LRU,Least Recntly Use)
    • 时钟算法(Clock)
  4. 更新页表项
    • 当页面首次被访问时,访问位和状态位需要更新。
    • 如果页面被写入,修改位也需要被设置。
    • 当页面从物理内存中置换出去时,如果修改位被设置,需要将页面内容写回磁盘,并更新状态位。
    • 加载新页面到物理内存时,需要更新页表中的页框号,并适当设置状态位和访问位。

其他概念

抖动现象:刚刚换出的页面马上又换入内存,刚刚换入的页面马上要换出。

驻留集:操作系统给进程分配的物理页框的集合。

工作集:进程实际访问页面的集合

交换区:在操作系统中,交换区(Swap Space)是一种用于扩展计算机的虚拟内存的机制。当物理内存(RAM)的使用接近其容量时,操作系统可以将当前不活跃的内存页面(即程序或数据的一部分)移动到交换区中。这样,RAM就能腾出空间来加载和执行其他程序或处理数据。交换区通常位于硬盘上,因此访问速度比直接访问物理内存慢得多。

页面置换算法

最佳置换算法

  • 英文:OPT,Optimal
  • 淘汰页面:往后寻找,当前内存中的页号最后一个出现的
  • 优缺点:理想化算法,无法实现

先进先出算法

  • 英文:FIFO
  • 淘汰页面:最早进入内存的页面
  • 优缺点:实现简单,算法性能差,会产生 Belady 异常
  • Belady是 给进程分配的物理块增多 反而缺页率增大

最近最久未使用置换算法

  • 英文:LRU,least recently used
  • 淘汰页面:向前寻找,当前内存中的页号最后一个出现的
  • 优缺点:性能好,但开销大

时钟置换算法

  • 英文:CLOCK
  • 思想:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成1个循环队列。
  • 循环扫描各页面,第一轮:淘汰访问位为 \(0\) 的,并将访问过的页面(访问位为 \(1\) 的页面)的访问位改为 \(0\) 。若一轮没选中,则进行第二轮。
  • 淘汰后指针是指向下一位
  • 优缺点:实现简单,性能也不错。

改进型CLOCK算法

  • (0,0)->(0,1)->(1,0)->(1,1)
  • (1,0) : 已访问,未修改,可能再被访问。所以在 (0,1) 后面。
  • 最多进行四轮
  • 减少磁盘的IO操作次数,增加了算法的开销。

页框分配

在请求分页系统中,可采用两种「内存分配策略」:固定和可变分配策略;在进行置换时,也有两种策略:全局置换和局部置换

全局替换:全局置换策略允许操作系统从整个系统的内存帧中选择要置换的页,而不仅仅是从发出请求的进程所拥有的内存帧中选择。这意味着操作系统可以根据整个系统的内存使用情况来做出更优的决策。

局部替换:在局部置换策略中,当某个进程需要更多的内存时,只能从该进程当前分配的内存中回收内存页。

固定分配+局部替换

可变分配+全局替换

可变分配+局部替换


Created: April 24, 2026
Last update: April 24, 2026

Discussion