内存管理:存储器管理

内存管理

内存管理的概念

image-20230329174303501

内存管理的主要功能:

  • 内存空间的分配与回收。由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储器分配的麻烦,提高编程效率
  • 地址转换。在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致,存储器必须系统地址变换功能
  • 内存空间的扩充。利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存
  • 内存共享。指允许多个进程访问内存的同一部分
  • 内存保护。保证各道作业在格子的存储空间内运行,互不干扰

内存管理的基本原理和要求

程序的链接与装入

image-20230329152922734

程序链接的三种方式

1.静态链接

程序运行之前,先将各目标模块及它们所需的库函数连接成一个完整的可执行文件(装入模块),之后不再拆开。

将几个目标模块装配成一个装入模块时,需要解决的两个问题:①修改相对地址,编译后的所有目标模块都是从0开始的相对地址,当链接成一个装入模块时要修改相对地址。②变换外部调用符号,将每个模块中所用的外部调用符号也都变为相对地址。

2.装入时动态链接

将各目标模块装入内存时,边装入边链接的链接方式

3.运行时动态链接

程序执行中需要该目标模块时,才对它进行链接。其优点是便于修改和更新,便于实现对目标模块的共享

程序装入的三种方式

绝对装入

装入方式只适用于单道程序环境。在编译时,如果知道程序将放到内存中的哪个位置,编译程序将产生绝对地址的目标代码。装入程序按照转入模块中的地址,将程序和数据装入内存。(编译或汇编时就将逻辑地址转化为绝对地址

image-20230329154709059

静态重定位装入

又称可重定位装入。编译、链接后的装入模块地址都是从0开始的,指令中使用的地址、数据存放的地址都是相对于初始地址而言的逻辑地址。可根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对地址进行重定位,将逻辑地址变换为物理地址(地址变换是在装入时一次完成的

静态重定位的特点是在一个作业装入内存时,必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入该作业。此外,作业在装入内存后,整个运行期间就不能在内存中移动,也不能申请内存空间

image-20230329155536354

动态运行时装入/动态重定位

编译链接后的装入模块的地址都是从0开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转化为物理地址,而是把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。这种方式需要一个重定位寄存器的支持。

动态重定位的优点:可以将程序分配到不连续的存储区;在程序运行之前可以只装入部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享。

image-20230329160521834

image-20230329160124064

三种装入方式最本质的区别其实就是何时将逻辑地址转化为物理地址。

  • 绝对装入。编译或汇编的时候就转化
  • 静态重定位。程序装入内存的时候转化
  • 动态重定位。程序运行的时候转化
逻辑地址与物理地址

编译后,每个目标模块都从0号单元开始编址,这称为目标模块的相对地址(或逻辑地址)。当链接程序将各个模块链接成一个完整的可执行目标程序时,链接程序顺序依次按各个模块的相对地址构成统一的从0号单元开始编址的逻辑地址空间(或虚拟地址空间),对于32位系统,逻辑地址空间的范围为0~ 2 32 − 1 2^{32} - 1 2321

物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址,进程在运行时执行指令和访问数据,最后都要通过物理地址从主存中存取。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换为物理地址,这个过程称为地址重定位。

操作系统通过内存管理部件(MMU)将进程使用的逻辑地址转换为物理地址。逻辑地址通过页表映射到物理内存,页表由操作系统维护并被处理器引用。

进程的内存映象

不同于存放在硬盘上的可执行文件,当一个程序调入内存运行时,就构成了进程的内存映像。一个进程的内存映像一般有几个要素:

  • 代码段:即二进制代码,代码是只读的,可以被多个进程共享
  • 数据段:程序运行时加工处理的对象,包括全局变量和局部变量
  • 进程控制块(PCB):存放在系统区。操作系统通过PCB来控制和管理进程
  • 堆:用来存放动态分配的变量。通过调用malloc函数动态地向高地址分配空间
  • 栈:用来实现函数调用。从用户空间的最大地址往低地址方向增长

代码段和数据段在程序调入内存时就指定了大小,而堆和栈不一样。当调用malloc和free这样的C标准库函数时,堆可以在运行时动态地扩展和收缩。用户栈在程序运行期间也可以动态地进行扩展和收缩,每次调用一个函数,栈就会增长;从一个函数返回,栈就会收缩

image-20230329171226200

内存保护

确保每个进程都有一个单独的内存空间。内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。内存保护可采取的两种方法:

方案一

在CPU中设置一对上、下限寄存器,用于存放用户作业在主存中的下限和上限地址,每当CPU访问一个帝制时,分别和两个寄存器的值对比,判断有无越界。

方案二

采用重定位寄存器基地址寄存器)和界地址寄存器限长寄存器)来实现这种保护。重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址的最大值

image-20230329172339639

这两个方案的本质区别在于寄存器作用的不同:

  • 方案一: 上下限寄存器都是用来和访问的地址比较的
  • 方案二:基地址寄存器是用来给要访问的地址“加”的,限长寄存器是用来和逻辑地址进行比的(可以看到上图要进行内存访问时,先利用限长寄存器进行比较)

覆盖与交换

image-20230329190729479

覆盖技术

覆盖技术的思想:

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

覆盖技术的特点是,打破了必须将一个进程的全部信息都装入主存后才能运行的限制,但当同时运行程序的代码量大于主存时任不能运行,此外,内存中能够更新的地方只有覆盖区的段,不在覆盖区中的段会常驻内存。必须由程序员声明覆盖结构,操作系统完成自动覆盖。缺点:对用户不透明

image-20230329184300709

交换技术

交换技术的思想:把处于等待状态(或在CPU调度原则下被剥夺运行权利)的程序从内存移到辅存,把空间腾出来,这一过程又称为换出;把准备好竞争的CPU运行程序从辅存移到内存,这一过程称为换入中级调度采用的就是交换技术。

在具有交换功能的操作系统中,通常把磁盘空间分为文件区对换区两部分。文件区主要用于存放文件,主要追求存储空间的利用率,因此文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入和患处速度,因此通常对换区采用连续分配方式对换区的I/O速度比文件区更快

image-20230329184944939

image-20230329185358914

✨✨ 交换技术主要在不同进程(或作业)之间进行,而覆盖则用于同一个程序或进程中。对于主存无法存放用户程序的矛盾,现代计算机通过虚拟内存技术来解决W,覆盖技术则已称为历史;而交换技术在现代操作系统中仍具有较强的生命力。普通的交换使用的不多,但交换策略的某些变体在许多系统(如UNIX)中仍发挥作用

连续分配管理

image-20230329212452332

单一连续分配

在单一连续分配方式中,内存被分为系统区用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据;用户区用于存放用户进程的相关数据。内存中只能有一道用户程序,用户程序独占整个用户区空间。

优点:实现简单;无外部碎片;可以采用覆盖技术扩充内存;不一定需要采用内存保护(早期的OC操作系统MS-DOS)

缺点:只能用于单用户、单任务的操作系统中;有内部碎片(如果分配给某进程的内存区域中,如果有些部分没有用上,就是“内部碎片”);存储器利用率极低

理解为什么这个叫单一连续分配?

因为除了系统区外所有空间都是一个用户的,这个区域的地址是连续的

image-20230329192401237

固定分区分配

固定分区分配将用户空间分割未若干个固定大小的分区,再每个分区中只装入一道作业,这样就形成了最早的、最简单的一种可运行多道程序的内存管理方式。在划分分区时有两种不同的方法:

  • 分区大小相等。程序大小会造成浪费,程序太大又无法接入,缺乏灵活性
  • 分区大小不等。划分未多个较小的分区、适量的中等分区和少量的大分区

如何避免重复分配一段内存空间、如何实现分配?

操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分欸与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的0起始地址状态(是否已分配)。

image-20230329193801912

当用户程序要装入内存时,①由操作系统内核程序根据用户程序大小检索该表,从中找到一个能满足大小的、未分配的分区,将之分配给该程序,然后修改状态未“已分配”

优点:实现简单,无外部碎片

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

外部****碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。

image-20230329193738373

动态分区分配

动态分区分配又称可变分区分配,它是进程装入内存时,根据进程的时机需求,动态地为之分配内存(不预先划分内存分区),并使分区的大小正好适合进程的需要。因此,系统中分区的大小和数目是可变的。动态分配没有内部碎片,但是有外部碎片。可以通过==紧凑(拼凑,Compaction)==技术来解决外部碎片问题。

  • 内部碎片:分配给某些紧凑的内存区域中,有部分没有用上
  • 外部碎片:是指内存中的某些空闲分区由于太小难以满足

后面我们来讨论一下动态分区分配的几个问题。

  1. 系统要用什么样的数据结构记录内存的使用情况?

通常采用空闲分区表空闲分区链,如下图所示。

image-20230329200909405

  1. 当很多个空闲分区都能满足需求时,应选择哪个分区进行分配?

如何按照一定的动态分区算法,从空闲的分区表中选出一个分区分配给该作业。在下一小节详细讲动态分区算法。

  1. 如何进去分区的分配与回收操作?

插入操作:如下图将进程5插入到内存底部

image-20230329203338424

回收内存,系统根据回收分区的始址,从空闲分区链中找到相应的从插入节点,此时可能出现四种情况:

① 回收分区与插入的前一空闲分区相邻,将这两个分区合并,并修改前一分区项的大小为两者之和;

image-20230329204350212

②回收区与插入点的后一空闲分区相邻,将这两个分区合并,并修改后一分区的其实地址和大小

image-20230329204420710

③回收区同时和插入点的前后、后两个空闲分区相邻,此时将这三个分区合并是,修改前一分区表项的大小为三者之和,取消后一分区表项

image-20230329204428412

④回收区没有相邻的空闲分区,此时为回收区新建一个表项,填写起始地址和大小,并插入空闲分区链

image-20230329204436513

动态分区分配算法——基于顺序搜素

解决问题若同时多个空闲分区都能满足需求时,应该选择哪个分区进行分配?

image-20230329215813314

首次适应算法(First Fit)

算法思想:每次都从低地址开始查找,找到第一个能满足大小的空闲分区

实现:空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区(或空闲分区表,找到大小能满足要求的第一个空闲分区)

首次适应算法最简单,通常也是最好和最快的。不过,首次适应算法会使得内存的低地址部分出现很多小的空闲分区,而每次分配查找时都要经过这些分区,因此增加了开销

最佳适应算法

算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即优先使用更小的空闲分区

实现:空闲分区按容量递增次序链接。每次分配内存顺序查找空闲分区(或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点:每次都选最小的分区进行分配,会留下越来越多的、很小的、难以利用的内存块。因此这种方法会产生很多的外部碎片

最坏适应算法

又称最大适应算法(Largest Fit)

算法思想:为了解决最佳适应算法的问题——即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续分区,这样分配后剩余的空闲区就不会太小,更方便使用。

实现:空闲分区按容量递减链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区

缺点:每次都选最大的分区进行分配,虽然可以让分配后留下的空闲区更大,更可用,但是这种方式会导致较大的连续空闲区被迅速用完。如果之后有“大进程”到达,就没有内存分区可用了。

领近适应算法

算法思想:首次适应算法每次都从链头开始查找。这可能会导致低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。

实现:空闲分区以地址递增顺序排列(可排列成一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表,找到大小能满足要求的第一个空闲分区)。

优点:使内存中的空闲分区分布得更均匀,从而减少了查找空闲分区时的开销

缺点:邻近适应算法常常导致在内存的尾部分裂成小碎片,通常比首次适应算法要差。

离散分配管理

基本分页存储管理

image-20230330221643689

连续分配的方式会形成许多“碎片”,虽然可以通过紧凑的方式将许多碎片拼接成可用的空间大小,但是须付出很大的开销。所以开始考虑允许将一个进程直接分散到许多不相邻接的分区中。根据在离散分配时所分配地址空间的基本单位不同,将离散分配分为以下三种:

  1. 分页存储管理。在该方式中,将用户程序的地址空间分为若干个固定大小的区域,称为“页”或“页面”。相应的内存空间分为若干个物理块或页框,页和块的大小相同。
  2. 分段存储管理。这种方法把用户程序的地址空间分为若干个大小不同的段,每段可定义一组相对完整的信息。在存储器分配时,以段为单位,这些段在内存中也可以不相邻
  3. 段页存储管理。将分页和分段两种存储管理方式进行结合的产物。它同时具有两者的优点,是目前应用比较广泛的一种存储管理方式
✨✨分页存储管理的基本方法
页面和物理块

页面

将内存空间分为一个个大小相等的分区(比如:每个分区4KB),每个分区就是一个==“页框”(页框= 页帧 = 内存块 = 物理块= 物理页面).每个页框有一个编号,即“页框号”(页框号= 页帧号 = 内存块号 = 物理块号 = 物理页面号)==,页框号从0开始

将进程的逻辑地址空间分为与页框大小相等的各个部分,每个部分称为==“页”或“页面”。每个页面对应的编号即“页号”==,页号也从0开始

操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框一一对应的关系。由于进程中最后一块往往装不满,因而会成为“页面碎片”

👀页框= 页帧 = 内存块 = 物理块 = 物理页面 区分于 页 = 页面

页面大小

这里主要讨论三种情况,页面过大、小、适合:

  • 页面过小:
    • 优:减小内存碎片,提高内存的利用率
    • 缺:造成每个进程占用较多的页面,从而导致进程的页表过长,占用大量内存。还会降低页面换进换出的效率
  • 页面过大:
    • 优:减小页表长度,提高页面换进换出的速度
    • 缺:页内碎片增大
  • 适合的页面大小往往是2的幂,通常为1KB~8KB

页面大小是2的整数幂的好处

  1. 逻辑地址的拆分更加迅速——如果每个页面大小为 2KB,用二进制数表示逻辑地址,则末尾 K 位 即为页内偏移量,其余部分就是页号。因此,如果让每个页面的大小为 2 的整数幂,计算机硬件就 可以很方便地得出一个逻辑地址对应的页号和页内偏移量,而无需进行除法运算,从而提升了运行速度。
  2. 物理地址的计算更加迅速——根据逻辑地址得到页号,根据页号查询页表从而找到页面存放的内 存块号,将二进制表示的内存块号和页内偏移量拼接起来,就可以得到最终的物理地址。
页表

页表的始址放在页表基址寄存器(PTBR)中

为了能知道进程的每个页面再内存中存放的位置,操作系统要为每个进程建立一张页表.``页表通常存在PCB(进程控制块)中`。

  1. 一个进程对应一张页表
  2. 进程的每个页面对应一个页表项
  3. 每个页表项由“页号”和“块号”组成
  4. 页表记录进程页面和实际存放的页框之间的映射关系
  5. 每个页表项的长度是相同的

页号不占用存储空间,理解为数据结构中的数组

image-20230330214014619

image-20230330215255084

image-20230330215550711

逻辑地址结构

分页存储管理的逻辑地址结构如下:

image-20230330215817041

地址结构包含两个部分:前一部分为页号,后一部分为页内偏移量。在上图的例子中,地址长度为32位,其中0~11位为页内偏移量,或称为页内地址;12 ~ 32位为页号

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

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

Tips:有些奇葩题目中的页面大小不是2的整数次幂,这种情况:

页号= 逻辑地址 / 页面长度(整除)

页内偏移量 = 逻辑地址 % 页面长度(取出发的余数部分)

image-20230401192535646

有块表的地址变换机构

快表,又称联想寄存器(TLB, translation lookaside buffer),是一种访问速度比内存快很多的高速缓存(TLB不是内存,实质上是一种SRAM),用来存放最近当问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表。(进程切换的时候快表的内容也会被清除)

image-20230401193449078

有的系统会同时访问快表和页表,若在快表中找到则中断快表的查询

有快表时访问逻辑地址的步骤:

  1. CPU给出逻辑地址,某个硬件算得页号、页内偏移量,将页号与快表中的所有页号进行比较
  2. 如果找到匹配的页号,说明要访问的页表项在快表中有副本,则直接从中读取出该页对应的内存块号,再将内存块号和页内偏移量拼接成物理地址,最后根据物理地址去访问对应的内存单元。因此若命中快表,则访问某个逻辑地址仅需一次访存
  3. 若未在快表中找到匹配的页号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号和页内偏移量拼接成物理地址,最后该物理地址对应的内存单元。因此,若快表未命中,则访问某个逻辑地址需要两次访存(注:在找到页表项后,同时将其放入快表),若出现快表已满,则按照一定的算法对旧的页表进行替换

快表的速度比查询页表的速度快很多,因此只要快表命中,就可以节省很多时间。因为局部性上原理,一般来说快表的命中率可达90%以上

image-20230401194817146

image-20230401195553063

两级页表

单页表存在的问题:

问题一:页表必须连续存放,因此当页表很大的时候,需要占用大量的连续页框。

问题二:没有必要让整个页表常驻内存,因为进程在一段时间内可能是需要访问某几个特定的页面

image-20230401201353746

二级页表就是把页表项再分页并离散存储,然后再建立一张页表记录各个部分的存放位置,称为==页目录表,或外层页表,或称为顶层页表==

采用这种结构其实就是将一张大的连续页表拆分为了多个页表,而这多个页表还可以不同时在内存中。

二级页表的结构

image-20230401204418179

如何实现地址变换

实现地址转换分为以下几步:

  1. 按照地址结构将逻辑地址拆分为三部分
  2. 从PCB中读出页目录表初始地址,再根据一级页号查页目录表,找到对应的那张页表在内存中的位置
  3. 根据二级页号查二级页表,找到想要访问的内存块号
  4. 结合业内地址偏移量得到物理地址

其实二级页表的查询和一级页表的查询只是多了一次根据一级页表查询到二级页表的过程,当然要是二级页表在内存外则需要发生缺页中断去辅存中调度二级页表

image-20230401210555236

采用二级页表后,要是第二级页表不在内存中怎么办?

答:一方面采用虚拟存储技术可在页目录表中增加是否在内存中这一列表示页面是否已经调入内存。

拓展成更高级页表

要是是分成两级页表后,页表还是很长,则可以采用更多级页表,一般来说页表的大小不能超过一个页面。这个可以这么理解,每个页表都是由上一级页指定的(也就是通过上一级页表的信息找到,第一级的则是通过PCB中的页目录始址来查找的)。这个指定一般是通过下对应的下一级页号的初始物理地址地址来来实现,所以一般只能指向一个页面,否则这个页表项的结构改变才可以做到

其实是套娃:数据是以页框为单位存储的,而这个页表项也需要用这个页框来进行存储,这个其实也就是多级页表的达到拆分页表的目的。所以除第一级页面后的页表大小应尽量等于一个页面的大小,这样子可以减少页内碎片

另外可以辅助下图来理解:

image-20230401220141195

分段存储

image-20230402100247259

为什么要引入分段存储管理,可以通过以下两个方面说明:

一方面是由于通常的程序都可分为若干个段,如主程序段、子程序段A……、数据段以及栈段等,每个段大多是一个独立逻辑单位;

另一方面,实现和满足信息共享、信息保护、动态链接以及信息的动态增长等需要,也都是以段为基本单位的

进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从0开始编址

内存分配规则:以段为单位进行分配(与分页管理的最大区别),每个段在内存中占据连续空间,但各段之间可以不相邻。段式存储会产生外部碎片

image-20230402102853593

段表

程序分为多个段,各个段离散地装入内存,为了保证程序能正常运行,就必须能从物理内存中找到各个逻辑段的存放位置。为此,跟分页存储类似,需要为每个进程建立一张段映射表,简称“段表”。

image-20230402104335037

地址变换

段式管理的访存逻辑地址的过程,其实和分页管理的很累死,不一样的就是是否检验了逻辑地址中的段内地址是否合法还有分段管理中段的长度是不同的

image-20230402104523945

image-20230402110914083

分段和分页管理的对比

信息的物理单位。分页的主要目的是实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户不可见

信息的逻辑单元。分段的主要目的是更好地满足用户需求。一个段通常包含着一组属于一个逻辑模块的信息。分段对用户是可见的,用户编程时需要显示地给出段名

页的大小固定且由系统决定,段的长度不固定,决定于用户编写的程序

分页的用户进程地址空间是一维,程序只需给出一个记忆符即可表示一个地址。

分段的用户进程地址空间是二维,程序员在标识一个地址时,既要给出段名,也要给出段内地址

image-20230402105540590

分段比分页更容易实现信息的共享和保护。不能修改的代码成为纯代码可重入代码(不属于临界资源),这样的代码是可以共享的。可以修改的代码是不能共享的

段一般比页大,所以段表项数目比页表项少,所需的联想存储器(快表/TLB)的大小也会相对较小,所以可以显著地减少存取数据的时间

访问一个逻辑地址需要几次访存?

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

image-20230402111928140

段页存储

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

✨段页式系统的基本原理是:分段和分页原理的结合,即现将用户程序分成若干个段,再把每个段分成若干个页,并为每个段赋予一个段名。会产生内部碎片。可以借助下图理解

image-20230402115530080

段页式存储的逻辑地址结构

段页式存储的地址结构由:段号段内页号业内地址三部分组成,如下图。段号决定了成分为几个段;段内页号代表每个段内最多有多少页;业内偏移量代表页面大小、内存块大小是多少

image-20230402115714489

段表、页表

每个段对应一个段表项,每个段表项由段号(虚拟存在,类似数组下标)、页表长度页表存放块号(相应页表起始地址)组成。每个段表项长度相等,段号是隐含的

每个页面对应一个页表项,每个页表项由页号、页面存放的内存块号组成。每个页表项长度相等,页号是隐含的

image-20230402120736995

地址变换过程

段页式系统的一次访问逻辑地址的过程(这里不考虑TLB):

  1. 根据逻辑地址得到段号、页号、业内偏移量
  2. 判断段号是否小于页表项数,若小于则继续执行,否则发生越界中断 第一次越界检查
  3. 根据PCB中的段表起始地址(物理地址)找到段表,并找到对应段表项存放的页表的起始地址(物理地址) (第一次访存
  4. 用页号和查到的段表中的页表长度(页表有几项/有几个页面)进行比较,若大于则发生越界中断,否则继续执行 (第二次越界检查
  5. 根据段内页号查找对应的表项,即找到对应页面指向的物理始址 (第二次访存
  6. 将页面对应的物理始址和页内偏移量进行拼接,得到得到最终数据所在的物理地址
  7. 访问目标内存单元(第三次访存

可以借助下图理解上述过程。可见若不使用TLB技术,段页式系统一次访问逻辑地址需要三次访存操作,两次次越界检查操作

image-20230402120813167

小结

image-20230402123142752

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值