当前位置: 首页 > news >正文

【学习笔记】计算机操作系统(四)—— 存储器管理

第四章 存储器管理

文章目录

  • 第四章 存储器管理
    • 4.1 存储器的层次结构
      • 4.1.1 多层结构的存储器系统
      • 4.1.2 主存储器与寄存器
      • 4.1.3 高速缓存和磁盘缓存
    • 4.2 程序的装入和链接
      • 4.2.1 程序的装入
      • 4.2.2 程序的链接
    • 4.3 连续分配存储管理方式
      • 4.3.1 单一连续分配
      • 4.3.2 固定分区分配
      • 4.3.3 动态分区分配
      • 4.3.4 基于顺序搜索的动态分区分配算法
      • 4.3.5 基于索引搜索的动态分区分配算法
      • 4.3.6 动态可重定位分区分配
    • 4.4 对换(Swapping)
      • 4.4.1 多道程序环境下的对换技术
      • 4.4.2 对换空间的管理
      • 4.4.3 进程的换出与换入
    • 4.5 非连续分配 - 分页存储管理方式
      • 4.5.1 分页存储管理的基本方法
      • 4.5.2 地址变换机构
      • 4.5.3 访问内存的有效时间
      • 4.5.4 两级和多级页表
      • 4.5.5 反置页表(Inverted Page Table)
    • 4.6 非连续分配 - 分段存储管理方式
      • 4.6.1 分段存储管理方式的引入
      • 4.6.2 分段系统的基本原理
      • 4.6.3 信息共享
    • 4.7 非连续分配 - 段页式存储管理方式

4.1 存储器的层次结构

内存:内存可存放数据。程序执行前需要先放到内存中才能被CPU处理——缓和CPU与硬盘之间的速度矛盾

存储单元内存被划分成的一个个小的、可独立寻址的空间,每个单元有唯一的地址并能存储固定大小的数据

内存地址从0开始,每个地址对应一个存储单元

“按字节编址”,则每个存储单元大小为 1字节,即 1B,即 8个二进制位
“按字编址”,则每个存储单元大小为 1个字;

1K = 210 ; 1M = 220 ; 1G = 230 ;

逻辑地址/相对地址相对于进程的起始地址而言的地址【程序经过编译、链接后生成的指令中指明的是逻辑地址】

物理地址/绝对地址内存硬件实际使用的唯一地址,直接对应内存芯片上的物理存储单元

操作系统与内存

  • 操作系统负责内存空间的分配与回收

  • 操作系统需要提供某种技术从逻辑上对内存空间进行扩充

  • 操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换

  • 操作系统需要提供内存保护功能。保证各进程在各自存储空间内运行,互不干扰

    • 方法一: 在CPU中设置一对上、下限寄存器,存放进程的上、下限地址。进程的指令要访问某个地址时,CPU检查是否越界

    • 方法二: 采用重定位寄存器(又称基址寄存器)界地址寄存器(又称限长寄存器)进行越界检查。重定位寄存器中存放的是进程的起始物理地址界地址寄存器中存放的是进程的最大逻辑地址

      在这里插入图片描述

进程映像

在这里插入图片描述

覆盖技术

  • 目的:解决“程序大小超过物理内存总和”的问题

  • 思想:

    • 程序分为多个段(多个模块)常用的段常驻内存,不常用的段在需要时调入内存,
    • 内存分为一个“固定区”若干个“覆盖区”
    • 需要常驻内存的段放在“固定区”中,调入后就不再调出(除非运行结束);不常用的段放在“覆盖区”需要用到时调入内存用不到时调出内存

在这里插入图片描述

交换/对换技术:内存空间紧张时,系统将内存中某些进程暂时换出外存,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度)

4.1.1 多层结构的存储器系统

1、存储器的多层结构

在这里插入图片描述

对于通用计算机而言,存储层次至少应具有三级: 最高层为CPU 寄存器中间为主存最底层是辅存

在较高档的计算机中,还可以根据具体的功能细分寄存器高速缓存主存储器磁盘缓存固定磁盘可移动存储介质6层

在存储层次中,层次越高(越靠近CPU)存储介质的访问速度越快价格也越高,相对所配置的 存储容量也越小

寄存器、高速缓存、主存储器和磁盘缓存均属于 操作系统存储管理 的管辖范畴,掉电后存储的信息不再存在

固定磁盘和可移动存储介质则属于 *设备管理 *的管辖范畴,存储的信息将被长期保存

2、可执行存储器

寄存器主存储器又被称为可执行存储器

进程可以在很少的时钟周期内使用一条load 或 store 指令对可执行存储器进行访问

辅存的访问需要通过I/O设备实现【涉及到中断、设备驱动程序以及物理设备的运行】,所需耗费的时间远远高于访问可执行存储器的时间。

4.1.2 主存储器与寄存器

1、主存储器
主存储器简称内存或主存,用于保存进程运行时的程序和数据,也称可执行存储器

通常,处理机都是从主存储器中取得指令和数据的,并将其所取得的指令放入指令寄存器中,而将其所读取的数据装入到数据寄存器中; 或者反之将寄存器中的数据存入到主存储器

主存储器访问速度远低于 CPU执行指令的速度,为缓和这一矛盾,在计算机系统中引入了寄存器和高速缓存。

2、寄存器
寄存器具有与处理机相同的速度,故对寄存器的访问速度最快,完全能与CPU协调工作,但价格昂贵。

4.1.3 高速缓存和磁盘缓存

1、高速缓存

  • 介于寄存器和存储器之间的存储器,主要用于备份主存中较常用的数据,以减少处理机对主存储器的访问次数,可大幅度地提高程序执行速度
  • 高速缓存容量远大于寄存器,而比内存小访问速度快于主存储器
  • 通常,进程的程序和数据存放在主存储器中,每当要访问时,才被临时复制到一个速度较快的高速缓存中。当CPU访问一组特定信息时,须首先检查它是否在高速缓存中,如果已存在,便可直接从中取出使用,以避免访问主存,否则,就须从主存中读出信息。

2、磁盘缓存

  • 磁盘的 I/O速度远低于对主存的访问速度,为了缓和两者之间在速度上的不匹配,而设置了磁盘缓存。
  • 用于暂时存放频繁使用的一部分磁盘数据和信息,以减少访问磁盘的次数
  • 它本身并不是一种实际存在的存储器,而是利用主存中的部分存储空间暂时存放从磁盘中读出(或写入)的信息

4.2 程序的装入和链接

在这里插入图片描述

4.2.1 程序的装入

在将一个装入模块装入内存时,可以有如下三种装入方式:【以下是无需进行链接的单个目标模块的装入过程】

1、绝对装入方式(Absolute Loading)

适用场景

  • 单道程序系统:计算机系统仅能运行单个程序,且内存分配固定。
  • 确定的内存位置:已知程序始终驻留在内存的固定区域(如起始地址为 R)。

绝对地址(物理地址)

编译/汇编时直接生成的目标代码中,地址为 真实的内存地址(如 0x5000)。

例:已知程序从地址 R 开始,编译后所有地址基于 R 生成(如变量地址为 R+0x100)。

时机:在编译时,逻辑地址就转换成物理地址

过程

  • 已知用户程序(进程)驻留在从R处开始的位置
  • 编译程序所产生的目标模块(即装入模块 ---- 包含绝对地址),便可从R处开始向上扩展
  • 绝对装入程序按照装入模块中的地址,将程序和数据装入内存
  • 程序中的逻辑地址与实际内存地址完全一致则无需重定位。

为什么绝对装入不适合多道程序?
→ 多程序需共享内存,固定地址会导致冲突。

符号地址的作用
→ 解耦逻辑与物理地址,通过编译阶段转换,提升可维护性

2、可重定位装入方式(Relocation Loading Mode)

适用场景

  • 多道程序环境:多个程序共享内存,编译时无法预知程序的实际加载位置。
  • 动态内存分配程序需灵活装入内存的任意空闲区域,而非固定地址。

逻辑地址(相对地址)

目标模块从地址 0 开始编址,程序内所有地址均为相对于起始地址的偏移量。

物理地址 = 逻辑地址 + 程序起始地址

静态重定位

  • 时机:程序 装入内存时 由装入器(Loader)一次性完成地址转换
  • 特点:重定位后地址固定不变,运行时无需再次转换

过程

  • 编译阶段:生成从 0 开始编址的目标模块(逻辑地址)。
  • 装入阶段
    • 分配内存空间(如起始地址 10000)。
    • 装入器遍历目标模块,将所有逻辑地址调整为物理地址(如 2500 → 12500)。
  • 执行阶段:CPU 直接使用重定位后的物理地址访问内存。

3、动态运行时的装入方式(Dynamic Run-time Loading)

适用场景

  • 需要动态内存管理的系统允许程序运行时被移动或换出/换入内存(如具有对换功能的系统)。
  • 现代多道程序环境:支持虚拟内存、进程调度和内存共享的高级操作系统(如Linux、Windows)。

动态重定位(Dynamic Relocation)

  • 时机地址转换推迟到程序执行时进行(而非装入时)。

  • 实现方式:通过 硬件支持(重定位寄存器: 存放装入模块存放的起始位置 实时计算物理地址。

    物理地址 = 逻辑地址 + 重定位寄存器值
    
  • 特点:

    • 程序装入后,内存中的地址仍为逻辑地址
    • CPU每次访问内存时,由MMU(内存管理单元)自动完成地址转换
    • 若进程被换出后换入到新位置,只需更新重定位寄存器,无需修改程序内的地址。
特性绝对装入静态重定位动态重定位
地址转换时机编译时装入时执行时
地址绑定方式绝对物理地址装入时根据起始地址修正运行时通过重定位寄存器转换
进程移动支持❌ 不可移动(固定地址)❌ 不可移动(装入后固定)✔️ 可换入/换出(动态更新基址)
硬件需求❌ 无需特殊硬件❌ 无需特殊硬件✔️ 需重定位寄存器(或MMU)
内存灵活性❌ 只能装入指定内存区域✔️ 可装入任意空闲区域✔️ 支持动态内存分配与共享
适用系统单道程序、嵌入式系统早期多道批处理系统现代多任务操作系统(如Linux/Windows)
典型场景裸机程序、ROM固化代码DOS时代程序进程对换、虚拟内存系统

4.2.2 程序的链接

源程序经过编译后,可得到一组目标模块。链接程序的功能是将这组目标模块以及它们所需要的库函数装配成一个完整的装入模块。链接分成如下三种。

1、静态链接(Static Linking)方式

事先进行链接而以后不再拆开的链接:先进行链接所形成的一个完整的装入模块【称可执行文件】。通常都不再把它拆开,要运行时可直接将它装入内存。

在将几个目标模块装配成一个装入模块时,须解决以下两个问题:

  • 对相对地址进行修改。在由编译程序所产生的所有目标模块中,使用的都是相对地址,其起始地址都为0,每个模块中的地址都是相对于起始地址计算的在链接成一个装入模块后,除去第一个模块其余在装入模块的起始地址不再是0,所以此时须修改其余模块中的相对地址。
  • 变换外部调用符号。将每个模块中所用的 外部调用符号也都变换为相对地址

2、装入时动态链接(Load-time Dynamic Linking)

在程序 装入内存时采用边装入边链接的链接方式——若调用外部模块,则**立即加载并链接** 对应的目标模块,且要 修改模块内的相对地址

装入时动态链接方式有以下优点:

1. 便于模块的修改与更新

  • 静态链接问题
    修改一个模块需重新链接所有依赖它的程序生成完整的新装入模块(低效且可能无法修改)。
  • 动态链接优势
    • 模块分开独立存放,修改或更新各目标模块
    • 下次程序装入时,自动链接新版本模块,无需重新编译其他部分

2. 支持模块共享

  • 静态链接问题:每个程序均包含所链接模块的 独立副本,浪费内存。
  • 动态链接优势内存中仅保留一份共享模块,所有程序通过地址映射共用同一物理副本——显著减少内存占用,尤其对公共库(如数学库、图形库)。

3、运行时动态链接(Run-time Dynamic Linking)

将对某些模块的链接推迟到程序执行时才进行

  • 在执行过程中,当发现一个被调用模块尚未装入内存时,立即由OS去找到该模块,并将之装入内存,将其链接到调用者模块上。
  • 凡在执行过程中未被用到的目标模块,都不会被调入内存和被链接到装入模块上

优点:加快程序的装入过程,而且可节省大量的内存空间

在这里插入图片描述

4.3 连续分配存储管理方式

为一个用户程序分配一个连续的内存空间,即程序中代码或数据的逻辑地址相邻,体现在内存空间分配时物理地址的相邻。

连续分配方式可分为四类: 单一连续分配固定分区分配动态分区分配以及动态可重定位分区分配

内部碎片,分配给某进程的内存区域中,如果有些部分没有用上。
外部碎片,是指内存中的某些空闲分区由于太小而难以利用。

4.3.1 单一连续分配

背景:早期单道批处理系统

核心思想:将内存划分为 系统区用户区,每次仅允许 一个用户程序独占用户区

内存布局

  • 系统区(低地址):存放操作系统内核(如监控程序、驱动程序)。
  • 用户区(高地址):整个空间由单个用户程序独占

优缺点

  • 优点:实现简单; 无外部碎片; 可以采用覆盖技术扩充内存; 不一定需要采取内存保护。
  • 缺点:只能用于单用户、单任务的操作系统中; 有内部碎片; 存储器利用率极低

4.3.2 固定分区分配

目的:支持 多道程序并发,解决单一连续分配的 单任务低效问题

核心思想

  • 将用户内存空间 预先划分 为若干 固定大小的分区每个分区装入一道作业,多道程序 共享内存
  • 各程序互不干扰(地址隔离),OS 通过 分区分配表 管理分区状态(已分配/空闲)。

1、划分分区的方法

  • 分区大小相等(指所有的内存分区大小相等)

    缺点是缺乏灵活性:

    • 当程序太小时,会造成内存空间的浪费。
    • 当程序太大时,一个分区又不足以装入该程序,致使该程序无法运行。
  • 分区大小不等。增加存储器分配的灵活性。对常在该系统中运行的作业大小进行调查,根据用户的需要来划分。通常,可把内存区划分成含有多个较小的分区、适量的中等分区及少量的大分区,便可根据程序的大小,为之分配适当的分区。

2、内存分配

将分区按其大小进行排队,并为之建立一张 分区使用表 ,其中各表项包括每个分区的起始地址大小状态(是否已分配)

核心思想:当有一用户程序要装入时,由内存分配程序依据用户程序的大小检索该表:

  • 若从中找到一个能满足要求的、尚未分配的分区,则将之分配给该程序,然后将该表项中的状态置为“已分配”
  • 未找到大小足够的分区,则拒绝为该用户程序分配内存。

优缺点

  • 优点: 实现简单,无外部碎片
  • 缺点:
    • 当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但这又会降低性能;
    • 会产生内部碎片,内存利用率低。

4.3.3 动态分区分配

动态分区分配又称为可变分区分配,它是在进程装入内存时,根据进程的实际需要,动态地为之分配内存空间。动态分区分配没有内部碎片,但是有外部碎片。

1、动态分区分配中的数据结构
常用的数据结构有以下两种形式:

  • 空闲分区表,在系统中设置一张空闲分区表,用于记录每个空闲分区的情况每个空闲分区占一个表目表目中包括分区号、分区大小和分区始址等数据项
  • 空闲分区链
    • 为了实现对空闲分区的分配和链接,在每个分区的起始部分设置一些用于控制分区分配的信息,以及用于链接各分区所用的前向指针,在分区尾部则设置一后向指针。通过前、后向链接指针,可将所有的空闲分区链接成一个双向链
    • 为了检索方便,在分区尾部重复设置状态位和分区大小表目。
    • 当分区被分配出去以后,把状态位由“0”改为“1”。此时,前、后向指针已无意义

在这里插入图片描述

2、动态分区分配算法
为把一个新作业装入内存,须按照一定的分配算法,从空闲分区表或空闲分区链中选出一分区分配给该作业。包括了传统的四种顺序式搜索算法以及三种较新的索引武搜索算法

3、分区分配操作

在动态分区存储管理方式中,主要的操作是分配内存回收内存

  • 分配内存

    在这里插入图片描述

  • 回收内存

    当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链(表)中找到相应的插入点,此时可能出现以下四种情况之一:

    • ① 回收区与插入点的前一个空闲分区F1相邻接:将两分区合并,形成新的空闲分区,不必分配新表项,只需修改:其前一分区F1的大小
    • ② 回收分区与插入点的后一空闲分区F2相邻接:将两分区合并,形成新的空闲分区,修改:用回收区的首址作为新空闲区的首址,大小为两者之和。
    • ③ 回收区同时与插入点的前、后两个分区邻接:将三个分区合并,形成新的空闲分区,修改:使用F1的表项和F1的首址,取消F2的表项,大小为三者之和
    • ④ 回收区既不与F1邻接,又不与F2邻接:修改:为回收区单独建立一个新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置

    在这里插入图片描述

4.3.4 基于顺序搜索的动态分区分配算法

顺序搜索,是指依次搜索空闲分区链上的空闲分区,去寻找一个其大小能满足要求的分区。比较适用于不太大的系统。

基于顺序搜索的动态分区分配算法有如下四种:

1、首次适应(first fit, FF)算法

核心思想:从 低地址 开始 顺序查找 空闲分区链, 第一个 大小满足条件的分区,进行分配。

分配流程

  • Step 1: 从链首(最低地址)开始顺序扫描
  • Step 2: 找到第一个大小 ≥ 请求大小的空闲分区
  • Step 3: 切割分区:分配所需的大小多余部分仍作为空闲块保留
  • Step 4: 若扫描完所有分区均不满足,返回分配失败
优点缺点
高效:查找速度快(通常低地址即可命中)。碎片化:低址部分易产生许多难以利用的、很小的空闲分区 - 碎片。
保留大块:高址部分可能留有大空闲区。分配不均:低址频繁切割,导致后续查找变慢。

2、循环首次适应(next fit,NF)算法

改进目标: 解决首次适应(FF)算法的以下问题:

  • 低址碎片化(低地址出现过多小碎片)。
  • 查找开销高(每次从链首开始扫描)。

核心思想:

  • 不每次都从链首开始查找,而是基于 上次分配位置(指针) 继续往后搜索。
  • 采用 循环查找 策略(到达链尾后跳回链首)。
  • 分配成功 后,**更新指针位置**到该分区的下一个空闲块。

算法流程

  1. 初始化:维护一个 起始查找指针(ptr) ,初始指向链首。
  2. 分配请求
    • Step 1: 从 ptr 位置开始顺序查找,检查当前空闲块是否满足请求大小。
    • Step 2: 若满足,切割分配并更新 ptr 到下一个空闲块。
    • Step 3: 若遍历到链尾仍未找到,则循环回链首继续查找。
    • Step 4: 若全链无满足块,返回失败。
优点缺点
减少低址碎片:避免集中切割低址部分。大块缺乏:分布均匀但可能无连续大空间。
查找效率更高:跳过低址已碎片化区域。仍存在碎片:外部碎片问题未彻底解决。

3、最佳适应(best fit,BF)算法

改进目标 :避免“大材小用”,提高内存利用率。

核心思想 :分配内存时,总是选择能满足请求且最小的空闲分区【空闲分区按大小升序排列,便于快速查找最佳匹配】,以减少浪费。

算法流程

  1. 空闲分区组织:所有空闲块按 容量从小到大排序
  2. 分配流程
    • Step 1: 扫描空闲分区链,找到第一个 ≥ 请求大小的分区。
    • Step 2: 若找到,切割分配,剩余部分作为新空闲块,重新排序。
    • Step 3: 若未找到满足块,返回分配失败
优点缺点
减少内部碎片,避免大块浪费。产生很多外部碎片(剩余部分极小)。
首次查找即最优,无需全链扫描。维护排序开销大(插入/删除频繁)。

4、最坏适应(worst fit,WF)算法

目标 :避免产生极小碎片,使得剩余部分仍可被后续利用。

核心思想 :每次分配时选择最大的空闲分区【将所有的空闲分区,按其容量以从大到小的顺序形成一空闲分区链,查找时,只要看第一个分区能否满足作业要求即可】,并从中切割所需大小。

算法流程

  1. 空闲分区排序:维护一个 按容量从大到小排列 的空闲链表。

  2. 分配步骤

    检查链表第一个分区(最大块)是否 ≥ 请求大小。

    • 满足 → 切割分配,剩余部分重新插入链表并排序
    • 不满足 → 直接分配失败(无足够大块)。
  3. 更新链表:将剩余空闲区(若有)重新按大小插入链表。

优点缺点
减少微小碎片(剩余部分较大)缺乏大块内存(频繁切割最大块)
查找效率高(只需检查首节点)分配大作业时可能失败(无连续大块)
适合中小型作业为主的场景维护降序链表开销较大(插入排序慢)

5、四种算法总结对比

算法分配策略分区排列顺序碎片特点适用场景
FF首次满足空闲分区以地址递增次序排列低址碎片集中需保留高址大块的情况
NF从上次位置继续查找空闲分区以地址递增次序排列(可排列成循环链表)碎片分散均匀避免低址碎片化
BF最小满足块空闲分区以容量递增次序排列外部碎片极多小内存频繁分配
WF最大满足块空闲分区以容量递减次序排列内部碎片少中小作业为主,避免碎片

4.3.5 基于索引搜索的动态分区分配算法

当系统很大时,系统中的内存分区可能会很多,相应的空闲分区链就可能很长,这时采用顺序搜索分区方法可能会很慢。为了提高搜索空闲分区的速度,在 大、中型系统 中往往会采用基于索引搜索的动态分区分配算法,目前常用的三种算法。

1、快速适应(quick fit)算法

核心思想 :又称分类搜索法,将空闲分区按固定大小分类,每类维护独立的链表,通过索引表快速定位。

目标

  • 高效查找直接定位最小满足块)。
  • 避免分割碎片分区不切割,减少外部碎片)。
  • 保留大分区(大块不会被切割,满足大作业需求)。

数据结构

  • 空闲分区链表

按容量分类:每类对应一个固定大小(如 2KB、4KB、8KB……)。【例:请求 3KB → 分配 4KB 链表中的块(向上取整)。】

  • 管理索引表

    哈希表或数组,存储每类链表的头指针

    索引表:
    | 2KB  |[2KB空块1][2KB空块2]NULL
    | 4KB  |[4KB空块1]NULL
    | 8KB  |[8KB空块1][8KB空块2][8KB空块3]NULL
    | ...  |
    

算法流程

  • Step 1:查找最小满足链表
    • 根据请求大小,从索引表中找到最小的 ≥ 需求容量的链表
    • 例:请求 5KB → 选择 8KB 链表(若 4KB 不满足)。
  • Step 2:分配首节点
    • 直接取出链表中第一个空闲块分配给进程(无需分割)。

优缺点

  • 优点

    • 查找效率极高:通过索引表直接定位链表,避免全局扫描。

    • 无外部碎片:分区整块分配,不切割。

    • 保留大分区:大块不会被切碎,适合大作业需求。

  • 缺点

    • 内部碎片不可避免:例:请求 3KB 分配 4KB,浪费 1KB(以空间换时间)。
    • 合并复杂度高:释放内存时需合并相邻空闲分区,需维护跨链表的合并逻辑(算法复杂)。
    • 分区固定化:若分类粒度不合理(如缺少 6KB 类),可能加剧浪费。

2、伙伴系统(buddy system)

在伙伴系统中,无论是占用块或空闲块,其大小均为 2的k 次幂(k 为某个正整数)例如;当用户申请n个字的内存区时,分配的占用块大小为 2k 个字(2k-1 < n ≤ 2k)

伙伴系统的优点是算法简单、速度快;缺点是由于只归并伙伴而容易产生碎片。

可利用空间表的结构

将所有大小相同的空闲块建于一张子表中。 每个子表是一个双重链表,双重链表中的结点结构:

​ head 为结点头部,是一个由 4 个域组成的记录,

  • llink 域rlink 域分别指向同一链表中的前驱和后继结点;

  • tag 域为值 取"0"、"1"的标志域;

  • kval 域的值为 2 的幂次 k;

  • space 是一个大小为 2k-1 个字的连续内存空间(仍假设 head 占一个字的空间)。

在这里插入图片描述

# define m 16
typedef struct WORD_b {struct WORD_b* llink; // 指向前驱结点int tag;// 块标志,0:空闲,l: 占用。int kval;// 块大小,值为 2 的幂次 Kstruct WORD_b* rlink;// 头部域,指向后继结点OtherType other; // 字的其他部分
}WORD_b, head; // WORD : 内存字类型,结点的第一个字也称为 headtypedef struct HeadNode {int nodesize; // 该链表的空闲块的大小WORD_b* first; // 该链表的表头指针
}FreeList[m+1]; // 表头向量类型

分配算法

在分配时经常需要将一个大的空闲块 分裂成两个大小相等 的存储区,这两个 由同一大块分裂出来的小块就称之“互为伙伴"

例题:

时间事件请求大小分配情况空闲情况
Start初始状态--210
T1A请求150B28(A)29, 28
T2B请求100B28(A), 27(B)29, 27
T3C请求50B28(A), 27(B), 26©29, 26
T4B释放-28(A), 26©29, 27, 26
T5C释放-28(A)29, 28
T6A释放--210

思路:

初始状态为210大小的空闲块

  • A进程分配150B (27 < 150 ≤ 28 ==> 2k-1 < 150 ≤ 2k, k = 8)分区时,首先计算应该分配在哪个k区 k=8
  • 接着,在2k对应的空闲分区链中查找
    • 找到,将空闲分区分配给进程A
    • 未找到,表示大小为2k的空闲分区已耗尽,需要 在大小为2k+1的空闲分区链中继续查找
      • 存在大小为2k+1的空闲分区,则将其等分为两个分区,这两个分区称为一对伙伴,其中一个用于分配,另一个加入大小为2k的空闲分区链。
      • 不存在大小为2k+1的空闲分区,则 继续查找2k+2的空闲分区链
        • 找到则需要进行两次分割,分割称两个2k+1的分区,一个2k+1大小的分区加入到对应的空闲分区链中; 另一个分区继续分割,分割成两个2k的分区,一个加入对应分区链中,一个分给进程。
        • 若仍然不存在则继续查找,以此类推

在这里插入图片描述

回收算法

首先判别其伙伴是否为空闲块

  • ,则只要将释放的空闲块简单插入在相应子表中即可;
  • ,则需在相应子表中找到其伙伴并删除之,然后再判别合并后的空闲块的伙伴是否是空闲块。依此重复,直到归并所得空闲块的伙伴不是空闲块时,再插入到相应的子表中去。

在这里插入图片描述

例如,当大小为28,起始地址为 512 的伙伴块的起始地址的计算方式为:
由于 512 取余 29=0,所以,512+ 28=768,即如果该存储块回收时,只需要查看起始地址为 768 的存储块的状态,如果是空闲块则两者合并,反之直接将回收的释放块链接到大小为 28 的链表中。

特点优点缺点
分配/释放速度快速查找递归分裂/合并 可能带来额外 CPU 开销
碎片控制几乎无外部碎片(自动合并空闲伙伴块)内部碎片严重
大块内存管理保留大块能力(合并机制避免大块被永久拆分)不灵活适配非2k请求(如申请3KB须分配4KB)
实现复杂度数据结构简单(仅需链表数组维护不同大小的块)频繁合并检查(释放时需递归检查伙伴块状态,影响性能)
适用场景适合大块连续内存分配不适合高频小内存分配

3、哈希算法

核心思想:用 哈希表 替代顺序索引表,将块大小作为关键字,直接映射到对应的空闲链表。

分配流程

  • 哈希表代替顺序索引表

    • 传统方式:按固定块大小(如 4KB, 8KB,…)维护索引表,查找时按顺序比对大小。
    • 哈希优化:将块大小作为 键(key),通过哈希函数 直接计算出链表位置,无需遍历。
  • 哈希函数设计

    冲突处理:若两个块大小映射到同一哈希桶(如 3KB 和 4KB 均映射到 4KB),可通过:

    • 链表法:在同一个桶内维护多个大小的链表。
    • 向上取整:强制分配更大块。
传统方式:
1. 请求 5KB → 遍历索引表找到 ≥5KB 的最小块(如 8KB)。
2. 访问 8KB 链表分配。哈希优化:
1. 请求 5KB → hash(5) 计算得到索引 5(或向上取整到 8)。
2. 直接访问哈希表[5] 或哈希表[8] 的链表,分配匹配块。

4.3.6 动态可重定位分区分配

1、紧凑

连续分配

  • 基本要求:程序和系统必须加载到连续的物理内存中。
  • 问题:随着程序不断分配和释放内存,内存会被分割成许多离散的小分区碎片化),即便总空闲空间足够,也可能无法满足大程序的连续分配需求。

碎片问题(内存零头)

外部碎片内存中存在多个不连续的小空闲分区,无法合并使用,即使它们的总和足够容纳新程序。
示例:

  • 内存中有 4 个空闲分区:10KB, 30KB, 14KB, 26KB(总计 80KB)。
  • 新作业要求 40KB 连续空间,由于没有单块 ≥40KB 的空闲区,无法分配。

解决方案:紧凑/拼接通过移动内存中作业的位置,把原来多个分散的小分区拼接成一个大分区

紧凑带来的问题

  • 地址改变:进程被移动后,其 内存基址(起始地址)改变,若不修改指令和数据的地址,将导致执行错误。
  • 频繁开销:内存碎片化快,需 频繁紧凑每次都要对移动了的程序或数据的地址进行修改,降低系统效率。

改进方案:动态重定位:程序在运行时不直接使用物理地址,而是通过基址寄存器(Bounds Register)动态计算

2、动态重定位

动态重定位(Dynamic Relocation),即在 运行时自动调整程序访问的物理地址,而 无需修改程序代码本身

重定位寄存器(Relocation Register):用它来存放程序(数据)在内存中的起始地址

硬件(MMU)自动完成 逻辑地址 → 物理地址的转换:物理地址 = 逻辑地址 + 重定位寄存器(基址)

在这里插入图片描述

3、动态重定位分区分配算法

动态重定位分区分配算法与动态分区分配算法基本上相同,差别仅在于:在动态重定位分区分配算法中,增加了紧凑的功能
当该算法不能找到一个足够大的空闲分区以满足用户需求时,如果所有的小的空闲分区的容量总和大于用户的要求,这时便须对内存进行“紧凑”,将经“紧凑”后所得到的大空闲分区分配给用户。

在这里插入图片描述

4.4 对换(Swapping)

4.4.1 多道程序环境下的对换技术

“对换”

  • 是指把内存中暂时不能运行的进程或者暂时不用的程序和数据换出到外存上,以便腾出足够的内存空间;
  • 再把已具备运行条件的进程进程所需要的程序和数据换入

对换的类型
在每次对换时,都是将一定数量的程序或数据换入或换出内存。按兑换数量换分为两类:

  • 整体对换
    • 以整个进程为单位的,故称之为“进程对换”或“整体对换
    • 处理机中级调度实际上就是存储器的对换功能,其目的是用来解决内存紧张问题,并可进一步提高内存的利用率和系统的吞吐量。
  • 页面(分段)对换
    • 进程的一个“页面”或“分段”为单位进行对换的,则分别称之为“页面对换”或“分段对换”,又统称为“部分对换”。
    • 目的是为了支持虚拟存储系统。

4.4.2 对换空间的管理

1、对换空间管理的主要目标

具有对换功能的 OS中,通常把磁盘空间分为文件区和对换区两部分对换区的I/O速度比文件区的更快

  • 文件区管理的主要目标
    • 文件区占用磁盘空间的大部分,用于存放各类文件
    • 通常的文件都是较长时间地驻留在外存上,对它访问的频率是较低的。
    • 对文件区管理的主要目标提高文件存储空间的利用率然后才是提高对文件的访问速度
    • 对文件区空间的管理采取离散分配方式。
  • 对换空间管理的主要目标
    • 对换空间只占用磁盘空间的小部分,用于存放从内存换出的进程
    • 这些进程在对换区中驻留的时间是短暂的,而对换操作的频率却较高
    • 对对换空间管理的主要目标,是提高进程换入和换出的速度然后才是提高文件存储空间的利用率
    • 对对换区空间的管理采取连续分配方式,较少考虑外存中的碎片问题

2、对换区空闲盘块管理中的数据结构

  • 用于记录外存对换区中空闲盘块的使用情况
  • 可以用空闲分区表空闲分区链
  • 在空闲分区表的每个表目中应包含两项: 对换区的首址及其大小,分别用盘块号盘块数表示。

3、对换空间的分配与回收

由于对换分区的分配采用的是连续分配方式,因而对换空间的分配与回收与动态分区方式时的内存分配与回收方法雷同

4.4.3 进程的换出与换入

1、进程的换出

进程换出(Swap Out)是内存管理的重要手段,当内存不足时,系统会将部分进程从内存调出至交换区(Swap Area),以腾出空间供其他进程运行。

选择被换出的进程

换出策略遵循**优先级+状态匹配**原则:

优先级顺序说明
阻塞/睡眠状态进程优先换出,因为它们当前不占用CPU
优先级最低的阻塞进程若多个阻塞进程存在,选优先级最低的
驻留时间较长的低优先级进程避免“刚换入就换出”的抖动问题
优先级最低的就绪进程如果无阻塞进程可选,换出就绪但低优先级的进程

📌 关键原则

  • 非运行状态优先(阻塞 > 就绪)
  • 低优先级优先
  • 考虑驻留时间(防止频繁换入换出)

进程换出流程

换出时需确保 共享数据不被破坏,步骤如下:

  1. 检查可换出内容
    • 只能换出非共享的程序段和数据段
    • 共享内存/代码段(如动态链接库)不可换出
  2. 申请交换区空间 :向磁盘交换区申请足够空间,若失败则终止换出操作。
  3. 数据写入磁盘 :启动磁盘I/O,将进程的**程序和数据从内存复制到交换区**。
  4. 释放内存资源(传输成功)
    • 回收该进程占用的 物理内存页
    • 更新相关数据结构
      • 进程控制块(PCB):标记为“换出”状态。
      • 内存分配表:记录释放的内存区域。
  5. 重复换出(可选) :若内存仍不足,继续选择下一个可换出进程,直到无阻塞进程或内存足够。

2、进程的换入

进程换入是对换机制的另一关键操作,当内存有空闲时,系统会将外存(交换区 / Swap Area)中符合条件的进程重新调入内存,使其恢复执行。

选择被换入的进程

换入策略遵循 就绪状态 + 换出时间 原则:

筛选条件说明
状态为“就绪且换出”只有就绪态的换出进程才可能被换入
换出时间最久(>阈值,如2s)优先换入长时间等待的进程,避免“饥饿”
无法换入时的处理若内存不足,先执行换出腾出空间,再换入

📌 关键原则

  • 公平性:防止某些进程因优先级低而长时间滞留外存。
  • 资源优化:避免频繁换入换出(抖动)。

进程换入流程

  1. 检查进程状态:扫描PCB集合,筛选所有 “就绪且换出” 的进程。

  2. 选择目标进程:从候选进程中,选择**换出时间最长(>2s)**的进程。

  3. 申请内存空间

    尝试为进程分配内存:

    • 成功:直接从外存加载到内存
    • 失败触发 换出操作 腾出空间,再换入
  4. 更新数据结构

    • PCB:标记为“就绪”状态,记录换入时间。
    • 内存分配表:记录新占用的物理页。
  5. 重复换入(可选)

    若内存仍有余量,继续换入其他“就绪且换出”进程,直到:无此类进程或内存不足。

4.5 非连续分配 - 分页存储管理方式

可将离散分配分为以下三种:

  • 分页存储管理方式
    • 用户程序的地址空间分为若干个固定大小的区域,称为“页”或“页面”。典型的页面大小为1KB。
    • 相应地,也将内存空间分为若干个物理块或页框(frame)页和块的大小相同
    • 这样可将用户程序的任一页放入任一物理块中,实现了离散分配。
  • 分段存储管理方式
    • 它把用户程序的地址空间分为若干个大小不同的段每段可定义一组相对完整的信息
    • 在存储器分配时,以段为单位,这些段在内存中可以不相邻接,所以也同样实现了离散分配。
  • 段页式存储管理方式。这是分页和分段两种存储管理方式相结合的产物。它同时具有两者的优点,是目前应用较广泛的一种存储管理方式。

4.5.1 分页存储管理的基本方法

1、【页、页面】和【物理块、页框、页帧、物理页(面)、内存块】

页面和物理块

  • 进程的逻辑地址空间分成若干个页,并为各页加以编号,从0开始(如第0页)。
  • 内存的物理地址空间分成若干个块,并为各块加以编号,从0开始(如0#块)。
  • 在为进程分配内存时,以块为单位将进程中的若干个分别装入到多个可以不相邻接的物理
  • 由于进程的最后一页经常装不满块,而形成了不可利用的碎片,称之为“页内碎片

页面大小页面的大小应选择适中,且页面大小应是2的幂,通常为1KB~8KB

  • 选择过小的页面大小:
    • 减小内存碎片,从而减少内存碎片总空间的作用,有利于内存利用率的提高
    • 造成每个进程占用较多的页面,从而导致进程的页表过长,占用大量内存。
    • 降低页面换进换出的效率。
  • 选择过大的页面大小:
    • 减少页表的长度,提高页面换进换出的速度,但却又会使页内碎片增大。

2、地址结构

两部分内容: 前一部分为页号P,后一部分为位(偏)移量W,即页内地址d

逻辑地址A对应的物理地址 = P号页面在内存中的起始地址 + 页内偏移量W

若给定一个逻辑地址空间中的地址为A页面的大小L,则页号P页内地址d可按下式求得:
P = I N T [ A L ] = A / L (取除法的整数部分) d = [ A ] M O D L = A % L (取除法的余数部分) 其中 I N T 是整除函数 , M O D 是取余函数。 P = INT[\frac{A}{L}] = A/L(取除法的整数部分) \quad d = [A]\,MOD\, L = A\%L(取除法的余数部分)\\其中 \,INT是整除函数,MOD是取余函数。 P=INT[LA]=A/L(取除法的整数部分)d=[A]MODL=A%L(取除法的余数部分)其中INT是整除函数,MOD是取余函数。
例如,其系统的页面大小为1KB, 设A=2170B,则由上式可以求得P=2,d=122。

在这里插入图片描述

如果有 K 位表示“页内偏移量”,则说明该系统中一个页面的大小是 2K 个内存单元

如果有 M 位表示“页号”,则说明在该系统中,一个进程最多允许有 2M 个页面

3、页表

页表的作用是实现从页号到物理块号的地址映射

在进程地址空间内的所有页(0~n),依次在页表中有一页表项,其中记录了相应页在内存中对应的物理块号。在配置了页表后,进程执行时,通过查找该表,即可找到每页在内存中的物理块号。

在这里插入图片描述

根据页号可以查询页表,而页表中记录的只是内存块号,而不是内存块的起始地址! J号内存块的起始地址 =J *内存块大小

4.5.2 地址变换机构

基本任务:将 用户地址空间中的逻辑地址转换内存空间中物理地址。实际上是借助页表将逻辑地址中的页号转换为内存中的物理块号

1、基本的地址变换机构

页表寄存器 PTR (Page-Table Register)

存储内容

  • 页表在内存的起始地址F【页表大多驻留在内存中】
  • 页表的长度M

内容来源

  • 进程未运行时:页表基址和长度保存在PCB中
  • 进程被调度时:从PCB加载到PTR

步骤详解:

  • 逻辑地址拆分(硬件自动完成):逻辑地址 = 页号(P) + 页内偏移量(W)

  • 越界检查(安全性):比较页号(P)页表长度M(PTR中存储):

    • P ≥ 页表长度 → 地址越界中断(非法访问)。【页号是从0开始的,而页表长度至少是1,因此 P=M 时也会越界】
    • P< 页表长度 → 未越界
      • 计算页表项位置页表项地址 = 页表始址(F) + 页号(P) × 页表长度(M)
      • 获取物理块号:从内存中读取页表项,得到物理块号
      • 合成物理地址物理地址 = 物理块号 × 页大小 + 页内偏移量(W)

    在这里插入图片描述

2、具有快表的地址变换机构 - 是基本地址变换机构的改进版本

背景:由于页表是存放在内存中的,这使CPU在每存取一个数据时,都要两次访问内存。

  • 第一次是访问内存中的页表,从中找到指定页的物理块号,再将块号与页内偏移量 W拼接,以形成物理地址。
  • 第二次访问内存时,是通过刚刚所得的物理地址获得所需数据(或向此地址中写入数据)。

因此,采用这种方式将使计算机的处理速度降低近1/2。

快表:又称联想寄存器(TLB, Translation Look aside Buffer),是一种访问速度比内存快很多的高速缓存(TLB不是内存!),用来存放最近访问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表。快表不可能做得很大,通常只存放16~512 个页表项

地址变换过程

在CPU给出有效地址(不越界)后,由地址变换机构自动地将页号P送入TLB,将此页号与TLB中所有页号进行比较

  • 若在快表中找到有与此相匹配的页号,便表示所要访问的页表项在快表中。于是,可直接从快表中读出该页所对应的物理块号,并送到物理地址寄存器中

  • 若在快表中未找到对应的页表项,则还须再访问内存中的页表,找到后把从页表项中读出的物理块号送往地址寄存器;
    同时,再将此页表项存入快表的一个寄存器单元中——重新修改快表。

    如果TLB已满,则OS必须找到一个老的且已被认为是不再需要的页表项,将它换出。

局部性定理:

时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行; 如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)

空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。(很多数据在内存中都是连续存放的)

基本地址变换机构中,每访问一个逻辑地址,都需要查询一次内存中的页表。由于局部性原理,可能连续很多次查到的都是同一个页表项。将慢表中的页表项复制到快表中,访问的速度就会大幅提升。

4.5.3 访问内存的有效时间

内存的有效访问时间(Effective Access Time, EAT):从进程发出指定逻辑地址的访问请求,经过地址变换,到在内存中找到对应的实际物理地址单元并取出数据,所需要花费的总时间。

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

在这里插入图片描述

4.5.4 两级和多级页表

单级页表的问题:
问题一:页表必须连续存放,因此当页表很大时,需要占用很多个连续的页框。
问题二:没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面。

解决问题一:两级和多级页表

将页表进行分页的方法,使每个页面的大小与内存物理块的大小相同,并为它们进行编号,然后离散地将各个页面分别存放在不同的物理块中。同样,也要为离散分配的页表再建立一张页表,称为外层页表(Outer Page Table)/页目录表/顶层页表,在每个页表项中记录了页表页面的物理块号。

在这里插入图片描述

注意:

在这里插入图片描述

解决问题二:

  • 可以在需要访问页面时才把页面调入内存(虚拟存储技术)。
  • 可以在页表项中增加一个标志位,用于表示该页面是否已经调入内存。如果没被调入内存中,则产生缺页中断(内中断),然后将目标页面从外存调入内存

4.5.5 反置页表(Inverted Page Table)

反置页表 则是为每一个物理块设置一个页表项,并将它们按物理块的编号排序,其中的内容则是页号和其所隶属进程的标识符

  • 全系统共享一个页表

  • 条目数=物理页框数 【条目数与物理内存相关】

    物理页框号(PFN) →  (进程ID + 页号)
    

地址转换流程:

  • 根据进程标识符和页号,去遍历检索反置页表。
    • 如果检索到与之匹配的页表项,则该页表项(中)的序号便是该页所在的物理块号,可用该块号与页内地址一起构成物理地址送内存地址寄存器。
    • 如果检索了整个反置页表仍未找到匹配的页表项,则表明此页尚未装入内存
      • 对于不具有请求调页功能的存储器管理系统,此时则表示地址出错
      • 对于具有请求调页功能的存储器管理系统,此时应产生请求调页中断,系统将把此页调入内存

检索优化

利用 Hash 算法来进行检索,这样可以很快地找到在反置页表中的相应页表项。

不过在采用 Hash 算法时,可能会出现所谓的“地址冲突”,即有多个逻辑地址被映射到同一个Hash 表项上,必须妥善解决这一问题。

4.6 非连续分配 - 分段存储管理方式

4.6.1 分段存储管理方式的引入

1. 方便编程

  • 逻辑分段:程序员可 将程序划分为多个逻辑段(如代码段、数据段、堆栈段等)。
  • 地址结构:逻辑地址由 段号+段内偏移 组成,直观易读。
  • 优点
    • 符合程序员的自然思维(函数、数组等逻辑单位独立编址)。
    • 调试和维护更直观(如直接定位到某个函数所在的段)。

2. 信息共享

  • 共享粒度:以为逻辑单位共享(如共享一个函数库或数据文件)。
  • 对比分页
    • 页是物理单位,共享一个函数可能需要多个不连续的页,管理复杂。
    • 段是逻辑单位,共享时只需标记整个段为可共享。

3. 信息保护

  • 保护粒度按段设置权限(如代码段只执行,数据段读写)。
  • 对比分页
    • 页可能混合不同权限的内容(如一个页同时包含代码和数据),无法统一保护。
    • 段是逻辑整体,保护标志直接作用于整个段(如 段X:只读)。
  • 用途防止越权访问(如恶意修改代码段)。

4. 动态增长

  • 需求场景数据段(如堆、数组)运行时可能动态扩展
  • 分段方案:预留空间或动态分配新物理段(操作系统调整段表)。
  • 对比分页/连续分配
    • 分页需预分配固定大小,扩展需分配新页表,可能引发碎片。
    • 连续分配(如动态分区)难以应对大小不确定的请求。

5. 动态链接

  • 核心思想:程序运行时按需加载和链接目标段(如调用函数时才加载)。
  • 分段支持以段为链接单位(如一个动态库对应一个段),延迟加载减少内存占用
  • 对比静态链接:避免一次性加载所有代码,提升内存利用率。

4.6.2 分段系统的基本原理

1. 分段

作业的地址空间被划分为若干个段每个段定义了一组逻辑信息且在内存中占据连续空间,但各段之间可以不相邻。例如,有主程序段 MAIN、子程序段X、数据段D及栈段S等。

每个段都有自己的名字。为了实现简单起见,通常可用一个段号来代替段名【编译程序会将段名转换为段号】每个段都从0开始编址,并采用一段连续的地址空间

段的长度由相应的逻辑信息组的长度决定,因此各段的长度并不相等

逻辑地址段号(段名)和段内地址所组成段号的位数决定了每个进程最多可以分几个段;段内地址位数决定了每个段的最大长度是多少

在这里插入图片描述

一维地址(如分页系统)
整个程序的内存地址是 连续编号 的,比如从01000,像一个长长的纸条。
→ 只需要指明“逻辑地址 = 第500号位置”,系统就能直接找到数据。

二维地址(分段系统)
程序的内存地址被分成多个段,每段有独立的编号和内部地址。
→ 需要指明:“逻辑地址 = <段号2, 偏移200> = 段号是2的第200号位置”,系统才会定位到数据。
先指定段(一维),再指定段内偏移(二维)】。

2. 段表

段表:用于实现从逻辑段到物理内存区的映射的。

段表:每个段在表中占有一个表项,其中记录了该段在内存中的起始地址(又称为“基址”)段的长度

段表可以存放在一组寄存器中,以利于提高地址转换速度。但更常见的方法是将段表放在内存中

在这里插入图片描述

3. 地址变换机构

系统中设置了段表寄存器,用于存放段表始址和段表长度TL

流程

  • 在进行地址变换时,系统将逻辑地址中的段号S与段表长度M, 进行比较
    • S ≥ M,表示段号太大,是访问越界,于是产生越界中断信号。
    • S < M,表示未越界, 则
      • 根据段表的始址F 和 该段的段号S计算出该段对应段表项的存放地址
      • 再检查段内地址W 是否超过该段的段长C
        • 若超过,即W ≥ C,同样发出越界中断信号。
        • 若未越界,即W < C,则将该段的基址b 与 段内地址W 相加,即可得到要访问的内存物理地址

在这里插入图片描述

访问内存

  • 分页(单级页表):第一次访存–查内存中的页表,第二次访存–访问目标内存单元总共两次访存
  • 分段:第一次访存–查内存中的段表,第二次访存–访问目标内存单元总共两次访存
  • 与分页系统类似,分段系统中也可以引入快表机构将近期访问过的段表项放到快表中,这样可以少一次访问,加快地址变换速度。

4. 分页和分段的主要区别

特性分段分页
划分单位逻辑段(变长)物理页(固定大小-系统决定)
地址转换段表(基址 + 段内地址)页表(页框号)
碎片问题外部碎片(需紧凑)内部碎片(页内未用空间)
用户可见性用户程序可感知(需指定段号)对用户透明(系统自动管理)
硬件成本段表寄存器页表寄存器
逻辑地址二维(段号 + 段内地址)一维

4.6.3 信息共享

分段比分页更容易实现信息的共享和保护。

在这里插入图片描述

4.7 非连续分配 - 段页式存储管理方式

1. 基本原理

段页式系统的基本原理是分段和分页原理的结合,即先将用户程序分成若干个段,再一个作业地址空间把每个段分成若干个页(面),并为每一个段赋予一个段名

优点缺点
分页管理内存空间利用率高,不会产生外部碎片,只会有少量的页内碎片不方便按照逻辑模块实现信息的共享和保护
分段管理很方便按照逻辑模块实现信息的共享和保护如果段长过大,为其分配很大的连续空间会很不方便。另外,段式管理会产生外部碎片

在这里插入图片描述

2. 段表、页表

  • 一个进程对应一个段表,每个段表项对应一个页表 => 一个进程对应多个页表
  • 段表每个段对应一个段表项,每个段表项段号页表长度页表存放块号(页表起始地址)组成。每个段表项长度相等,段号是隐含的
  • 页表每个页面对应一个页表项,每个页表项页号页面存放的内存块号组成。每个页表项长度相等,页号是隐含的

在这里插入图片描述

3. 地址变换过程

过程

  • 由逻辑地址得到段号页号页内偏移量

  • 段号与段表寄存器中的段长度比较检查段号是否越界

  • 段表始址、段号找到对应段表项

  • 根据段表中记录的页表长度,检查页号是否越界

  • 段表中的页表地址、页号得到查询页表,找到相应页表项

  • 由页面存放的内存块号、页内偏移量得到最终的物理地址

  • 访问目标单元

共三次访存。可引入快表机构,用段号和页号作为查询快表的关键字。老若快表命中则仅需一次访存。

在这里插入图片描述


参考:

教材:

计算机操作系统(第四版) (汤小丹) (Z-Library).pdf

视频:

王道计算机考研 操作系统

相关文章:

  • 懒汉式单例模式的线程安全实现
  • 医疗机械中丝杆支撑座有什么特殊要求?
  • 案例分析组合投资策略的回测与绩效分析
  • LLM学习笔记(六)线性代数
  • buuctf Crypto-鸡藕椒盐味1
  • Rust 数据结构:String
  • 后端框架(3):Spring(1)
  • IntelliJ IDEA打开项目后,目录和文件都不显示,只显示pom.xml,怎样可以再显示出来?
  • 西门子 S1500 PLC 通过 Profinet 对 6 台施耐德 ATV304 变频器的控制,用于 6 台升降台的位置控制。
  • Lua中使用module时踩过的坑
  • K8S从Harbor拉取镜像
  • Go语言处理HTTP下载中EOFFailed
  • Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件
  • 力扣654题:最大二叉树(递归)
  • React底层架构深度解析:从虚拟DOM到Fiber的演进之路
  • spring cloud gateway 源码解析
  • 火山引擎AI大模型
  • 经典启发算法【早期/启发式/HC爬山/SA模拟退火/TS禁忌搜/IA免疫 思想流程举例全】
  • Socket echo server
  • 成功案例丨从草图到鞍座:用先进的发泡成型仿真技术变革鞍座制造
  • 东部沿海大省浙江,为何盯上内河航运?
  • 《五行令》《攻守占》,2个月后国博见
  • 美联储计划裁员约10%
  • 夜读丨什么样的前程值得把春天错过
  • 李强:把做强国内大循环作为推动经济行稳致远的战略之举
  • 中国结算澄清“严查场外配资”传闻:账户核查为多年惯例,无特殊安排