目录

  • 1 内存管理背景
  • 2 固定分区分配
  • 3 动态内存分配
    • 3.1 首先适应 (First-fit)
    • 3.2 最佳适应 (Best-fit)
    • 3.3 外碎片问题
  • 4 分页
  • 5 分页硬件支持
  • 6 分段管理

1 内存管理背景

下图是计算机系统中存储层次结构:

本文主要讨论的是其中的 主存 (primary storage) 部分。计算机程序在执行过程中,所有程序必需放入内存并放入一个进程才能被执行,程序是磁盘中的一个静态的实体,通常对应着一个文件,所以的程序都是在输入队列中等待的,所谓输入队列就是磁盘上等待进入内存并执行的进程的集合。用户程序在执行之前必需经历很多步骤,这里可以以C语言为例参考我的这篇文章 C语言-用gcc指令体验C语言编译过程,如下图所示:

在程序装入内存中,存在着逻辑地址到物理地址的映射问题,即在逻辑地址中x的地址是200,但在物理地址中x的地址是1200,因为实际内存中不可能都是从地址0开始的,如下图:

因此需要地址之间的绑定以便于指令能够找到实际的物理地址,指令和数据绑定到内存地址可以在三个不同的阶段发生:

  • 编译时期:如果内存位置已知,可生成绝对代码;如果开始位置改变,需要重新编译代码;
  • 装入时期:如果存储位置在编译时不知道,则必须生成可重定位代码,实际上进程在内存中是不可以移动的,若要移动进程则需要重新定位;
  • 执行时期:如果进程在执行时可以在内存中移动,则地址绑定要延迟到运行时。需要硬件对地址映射的支持,例如基址和限长寄存器。

下图是三种绑定阶段的示例图。在编译时绑定,则在编译后就明确指出操作的物理地址,即move 1156 3表示把count的值放到地址为1156的位置;在加载时绑定,则在编译后就明确指出操作的逻辑地址,即move 156 3,在加载到内存后进行变换,变换到1156的位置;在运行时绑定,则在编译后也是只能给出逻辑地址,在加载到内存时,依然保存的是逻辑地址,但是当执行到这条语句时,再执行该指令的地址变换1000+156=1156

上文所提及的逻辑地址物理地址两个概念会贯穿于整个内存管理内容中,他们的定义如下:

  • 逻辑地址:由CPU产生;也叫做虚拟空间;
  • 物理地址:内存设备所读入的地址。

在上面的图中,指令move 1156 3中的1156就是逻辑地址,内存中的1156地址块就是物理地址,可以发现在编译时绑定和加载时绑定中,逻辑地址和物理地址是相同的,但在运行时绑定中,逻辑地址和物理地址是不同的。

我们把将程序装入到与其地址空间不一致的物理空间,所引起的一系列地址变换过程叫做地址重定位,地址重定位分为如下两种:

  • 静态地址重定位:在装入一个作业时,把作业中的指令地址全部转换为绝对地址,在作业执行过程中就无须再进行地址转换工作,如下图:
  • 动态地址重定位:动态地址重地位是在程序执行过程中,在CPU访问内存之前,将要访问的程序或数据地址转换成内存地址。动态重定位依靠硬件地址变换机构完成,如下图:

    通过硬件把虚拟地址映射到物理地址,所需的硬件叫做内存管理单元(MMU),在MMU策略中,基址寄存器中的值被加入到用户进程所产生的每个地址中,在其送入内存的时候,用户程序所对应到的是逻辑地址,物理地址对它从来都不可见,如下图:

2 固定分区分配

上一节中讲的主要内容是如何把程序放入内存,即要实现逻辑地址到物理地址的映射,使之能够正确的运行,这一节所讲的主要内容是研究放入内存后如何给它分配内存空间,通常来说会为一个程序分配一段连续的内存空间,主要有:

  • 单一连续区管理方式:主要针对单道批处理系统,只有一个作业进入内存,内存被分为两块,一块用来存放操作系统,一块用来存放用户程序,我们只要保证用户程序不会影响到操作系统即可,使用基址寄存器策略来保护用户进程(同其他进程和改变的操作系统代码和数据分开),基址寄存器包含最小物理地址的值,即起始地址;限长寄存器包含逻辑地址的范围,每个逻辑地址必需比限长寄存器的值小,即不能地址越界,判断地址合法流程图如下:
  • 多分区管理方式:是一种可用于多道程序的较简单的存储管理方式,它又分为固定分区方式可变分区方式。

对于固定分区分配方式,固定式分区是在作业装入之前,内存就被划分成若干个固定大小的连续分区,划分工作可以由系统管理员完成,也可以由操作系统实现,一旦划分完成,在系统运行期间不再重新划分,即分区的个数不可变,分区的大小不可变,所以,固定式分区又称为静态分区划分分区的方法如下:

  • 分区大小相等:比如有100MB内存,分五个分区,每个分区20MB,只适用于多个相同程序的并发执行(处理多个类型相同的对象),缺乏灵活性,会造成内碎片问题;

内碎片:比如一个分区大小是20MB,但是进程只需要16MB,多出的4MB用不上,而别的进程也无法使用,这4MB大小的空间就叫做内碎片。

  • 分区大小不等:多个小分区、适量的中等分区、少量的大分区。根据程序的大小,分配当前空闲的、适当大小的分区,两种划分方法示意图如下图所示:

一般将内存的用户区域划分成大小不等的分区,可适应不同大小的作业的需要。当作业到来时,系统有一张分区说明表,每个表目说明一个分区的大小、起始地址和是否已分配的使用标志,分区说明表和内存分配图如下图所示:

总结来说固定分区分配的优点是易于实现,开销小;缺点是分区大小固定,会造成内碎片问题,同时由于分区总数固定,会限制并发执行的进程数目。

3 动态内存分配

在动态分区分配中,分区的划分是动态的,不是预先确定的,当某个进程到来,它需要多少内存就给它分配多少内存,所以造成不同大小的分区分布在整个内存中,分配过程如下图:

在这种方式下,操作系统也是需要知道内存的状态的,可以采用空闲分区表空闲分区链两种方式,如下图:

在可变分区分配时要设计分区分配算法来寻找某个空闲分区,其大小需大于或等于程序的要求。若是大于要求,则将该分区分割成两个分区,其中一个分区为要求的大小并标记为“占用”,而另一个分区为余下部分并标记为“空闲”。分区的先后次序通常是从内存低端到高端。同时也要设计分区释放算法把相邻的空闲分区合并成一个空闲分区。(这时要解决的问题是:合并条件的判断)。

那么怎样从一个空的分区序列中满足一个申请需要?有如下三种方式:

  • 首先适应 (First-fit):分配最先找到的合适的分区;
  • 最佳适应 (Best-fit):搜索整个序列,找到适合条件的最小的分区进行分配;
  • 最差适应 (Worst-fit):搜索整个序列,寻找最大的分区进行分配。

很显然,在速度和存储的利用上,首先适应和最佳适应要比最差适应好。

3.1 首先适应 (First-fit)

首先适应的思想是从空闲分区表的第一个表目开始查找,把找到的第一个满足要求的空闲区分配给作业,目的在于减少查找时间。通常将空闲分区表(空闲区链)中的空闲分区要按地址由低到高进行排序,它有如下特点:

  • 分配和释放的时间性能较好,较大的空闲分区可以被保留在内存高端;
  • 随着低端分区不断划分而产生较多小分区,每次分配时查找时间开销会增大;
  • 在系统不断地分配和回收中,必定会出现一些不连续的小的空闲区,称为外碎片。虽然可能所有碎片的总和超过某一个作业的要求,但是由于不连续而无法分配。

外碎片:比如一块内存中依次分配了三个进程 P1P_1P1​,P2P_2P2​,P3P_3P3​,其中 P2P_2P2​ 占 20MB,此时 P2P_2P2​ 运行结束了,释放掉了自己的内存,然后来了一个新进程 P4P_4P4​,P4P_4P4​ 需要 18MB 的内存,恰好刚刚释放掉了 P2P_2P2​ 的20MB内存可以存放,但是会有 P4P_4P4​ 和 P3P_3P3​ 之间会有一个 2MB 的内存,由于它太小了,很难分配到它,所以这 2MB 内存就叫做外碎片。

3.2 最佳适应 (Best-fit)

最佳适应的思想是从全部空闲区中找出能满足作业要求的、且最小的空闲分区,能使碎片尽量小。为了提高查找效率,空闲分区表(空闲区链)中的空闲分区要按从小到大进行排序, 自表头开始查找到第一个满足要求的自由分区分配,它有如下特点:

  • 从个别来看,外碎片较小,但从整体来看,会形成较多无法利用的碎片;
  • 较大的空闲分区可以被保留。

下面是一个具体的例子,加入要分配一个16KB分区:

3.3 外碎片问题

在可变分区系统不断地分配和回收中,必定会出现一些不连续的小的空闲区,称为外碎片。虽然可能所有碎片的总和超过某一个作业的要求,但是由于不连续而无法分配。解决碎片的方法是拼接(或称紧凑),即向一个方向(例如向低地址端)移动已分配的作业,使那些零散的小空闲区在另一方向连成一片,但分区的拼接技术,一方面要求能够对作业进行动态重定位,另一方面系统在拼接时要耗费较多的时间,下图是一个拼接的例子,存在着400K300K200K三个外碎片,可以将其朝高地址拼接,也可以移动某个进程,也可以在中间拼接:

4 分页

上面所提到的用拼接解决外碎片问题在实现的时候还是有很多障碍的,我们需要思考还有没有别的方法来解决外碎片问题,我们首先来看动态分区产生外碎片的原因是什么?这是因为这种分配要求把作业必须安置在一连续存储区内的缘故;那么如果允许物理地址空间非连续,是否可以解决?分页存储管理是解决存储碎片的一种方法,要避开连续性要求,允许进程的物理地址空间不连续

分页的基本思想是进程的物理地址空间可以是不连续的,如果有可用的物理内存,它将分给进程。我们把物理内存分成大小固定的块。把逻辑内存也分为固定大小的块,叫做页,要求页的大小和块的大小是一样的,如下图所示:

根据上图可以看出,把逻辑内存划分为块之后,可以离散的分布在物理内存中。当然在这种情况下,操作系统需要知道哪些页是空闲的,运行一个有N页大小的程序,需要找到N个空的页框读入程序,还要解决的问题就是逻辑地址到物理地址的映射,我们是通过建立一个页表,把逻辑地址转换为物理地址。此外,由于内存块的划分是采用固定大小分配的,所以不可避免的会在最后一个页中产生内碎片,地址映射如下图所示:

我们知道由CPU产生的地址是逻辑地址,CPU 产生的地址被分为:

  • 页号 p (Page number):它包含每个页在物理内存中的基址,用来作为页表的索引,也就是一个程序会被划分为多个块,对应在物理地址中是多个页,页号指明了具体是哪个页;
  • 偏移 d (Page offset):同基址相结合,用来确定送入内存设备的物理内存地址,也就是一个页内有很多地址,偏移是确定具体是哪个地址。

通过页号和偏移确定物理地址的过程如下图,通过页号 p 去查找页表 page table,找到在页表中的哪个页 f,然后把 f 取出来再加上偏移 d,就可以映射到所在的物理地址:

总结来说分页解决了外碎片问题,但是会有内碎片,不过每个内碎片不会超过页的大小,这个开销相比之前的方法来说是可以接受的。一个程序不必连续存放,但也要求程序全部装入内存才能执行。

5 分页硬件支持

回顾分页的过程,如下图,在页数比较小的时候可以直接把页表放入寄存器,但当页数很多的时候,显然是要将页表放入内存中:

将页表放入内存后,要知道放在了内存的哪个地方,这里引入了两个寄存器来保存页表的位置:

  • 页表基址寄存器 Page-table base register (PTBR):页表基址寄存器指向页表的起始地址;
  • 页表限长寄存器 Page-table length register (PRLR):页表限长寄存器表明页表的长度。

在这个机制中,每一次的数据/指令存取需要两次内存存取,一次是存取页表,一次是存取数据,两次的存取显然性能不高,解决办法是通过一个联想寄存器 translation look-aside buffers (TLBs),可以解决两次存取的问题。

联想寄存器类似于一个快速缓存,每次查找一个页的时候,都记录下页和页的起始地址,当下次查询的时候可以直接在联想寄存器中寻找,找不到的时候再去查找页表,此时地址映射的过程如下,相比在第四节中最后的那张图多了一个联想寄存器的查找步骤:

我们知道寄存器的存取速度是比内存快的,因此用这种方法能大大提高查找效率,举个例子,我们假设联想寄存器的查找需要时间 εεε,内存一次存取要111微秒,我们称如果在联想寄存器中找到了对应的页地址的话,叫做“命中”,那么命中率 ααα 就为在联想寄存器中找到页号的比率,比率与联想寄存器的大小有关,此时有效的存取时间 T=(1+ε)α+(2+ε)(1–α)=2+ε–αT=(1 + ε) α + (2 + ε)(1 – α)=2 + ε – αT=(1+ε)α+(2+ε)(1–α)=2+ε–α。

可以带入具体数值来看一看,例如,假设检索联想存储器的时间为 20ns20ns20ns ,访问内存的时间为 100ns100ns100ns ,访问联想存储器的命中率为 85% ,则 CPU 存取一个数据的平均时间为 T=0.85∗120+0.15∗220=135nsT=0.85*120+0.15*220=135nsT=0.85∗120+0.15∗220=135ns,访问时间只增加 35%。如果不引入联想存储器,其访问将延长一倍(达 200ns200ns200ns )

下图是分页地址变换机构工作原理图,首先按页的大小分离出页号和位移量,放入有效地址寄存器中,再将页号与页表长度进行比较,如果页号大于页表长度,越界中断;再以页号为索引查找页表:将页表始址与页号和页表项长度的乘积相加,便得到该表项在页表中的位置,于是可从中得到该页的物理块号;然后将该物理块号装入物理地址寄存器的高址部分;最后将有效地址寄存器中的位移量直接复制到物理地址寄存器的低位部分,从而形成内存地址:

下面是一个具体的例子,图中省略了越界判断,先分离出了页号和偏移,分别为 21C4,然后查找页表,得到块号地址为 8,然后将 8 放在物理地址寄存器的高位,把偏移 1C4 放在物理地址寄存器的低位,这个地址就是物理地址:

6 分段管理

上面所讨论的分页方式有效的解决了外碎片问题,但是实际上并没有考虑用户的观点,也就是它在分页的时候都是硬性的按照等大小来划分,并不关心页中存放的是程序还是数据。本节中引入的分段方式就是一种支持用户观点的内存管理机制。

一个程序是一些段的集合,一个段是一个逻辑单位,如主程序、子过程、函数、局部变量、全局变量等等内容,在用户的眼里是把程序看作各个有机的部分,如下图:

把程序的各个部分放入内存实际上也就是把这每个部分看成各个段,然后放入内存,如下图:

在分段管理方式下要解决的问题依旧是逻辑地址到物理地址的映射问题,与分页类似,分段管理方式下也有段表,和段偏移。由于分页的每一页都是固定大小的,所以只需要起始地址,但是分段的每一段大小是不等长的,所以这里定义了两个变量:

  • 基址 (base):包括内存中段物理地址的起始地址;
  • 限长 (limit):指定段的长度;

从逻辑地址到物理地址的映射过程如下图所示,段表中保存着每一段的起始地址和线长地址,这样就在内存中唯一确定了段的地址范围:

下图是实现地址映射的物理结构流程图,其过程和分页的过程十分类似:

在分页方式中,页表是要保存在内存中的,所以当时定义了页表基址寄存器(PTBR)和页表限长寄存器 (PRLR)来指明页表的位置,同样在分段方式中,也定义了类似的两个寄存器:

  • 段表基址寄存器 Segment-table base register (STBR):段表基址寄存器指向段表在内存中的地址;
  • 段表限长寄存器 Segment-table length register (STLR):段表限长寄存器表明被一个程序所使用的段的数目。

此时地址变化过程如下图,首先系统将逻辑地址中的段号 S 与段表长度 TL 进行比较。若 S≥TL,访问越界,若未越界,则根据段表的始址和该段的段号,计算出该段对应段表项的位置,从中读出该段在内存中的起始地址;然后再检查段内地址 d 是否超过该段的段长 SL 。若超过,即 d≥SL,同样发出越界中断信号;若未越界,则将该段的基址与段内地址 d 相加,得到要访问的内存物理地址。

操作系统原理第八章:内存管理相关推荐

  1. 操作系统(三)内存管理

    操作系统(三)内存管理 一.程序执行过程 装入的三种方式 链接的三种方式 二.内存管理的概念 内存空间的分配与回收 连续分配管理方式 单一连续分配 固定分区分配 动态分区分配 首次适应算法 最佳适应算 ...

  2. (王道408考研操作系统)第三章内存管理-第二节1:虚拟内存管理基本概念

    文章目录 一:传统存储管理方式的弊端 二:局部性原理与高速缓冲技术Cache (1)Cache基本原理 (2)局部性原理 三:虚拟内存的定义和特征 (1)定义 (2)特征 四:虚拟内存实现 内存管理需 ...

  3. 操作系统概念学习笔记 15 内存管理(一)

    操作系统概念学习笔记 15 内存管理(一) 背景 内存是现代计算机运行的中心.内存有非常大一组字或字节组成,每一个字或字节都有它们自己的地址.CPU依据程序计数器(PC)的值从内存中提取指令.这些指令 ...

  4. 操作系统概念学习笔记 16 内存管理(二) 段页

    操作系统概念学习笔记 16 内存管理 (二) 分页(paging) 分页(paging)内存管理方案允许进程的物理地址空间可以使非连续的.分页避免了将不同大小的内存块匹配到交换空间上(前面叙述的内存管 ...

  5. 操作系统课设之内存管理

    前言 课程设计开始了,实验很有意思,写博客总结学到的知识 白嫖容易,创作不易,学到东西才是真 本文原创,创作不易,转载请注明!!! 本文链接 个人博客:https://ronglin.fun/arch ...

  6. (王道408考研操作系统)第三章内存管理-第二节3:页面置换算法2

    上接: (王道408考研操作系统)第三章内存管理-第二节2:页面置换算法1 文章目录 一:时钟置换算法(CLOCK) (1)简单时钟置换算法 (2)改进型时钟置换算法 二:页面置换算法总结 一:时钟置 ...

  7. 操作系统第三章-内存管理

    写在前面:本文参考王道论坛的 操作系统考研复习指导单科书 下面的流程图很重要. 加入快表的基本分页 加入快表的二级页表!! 虚拟存储器:请求分页的流程图. 文章目录 第三章 内存管理 3.1 内存管理 ...

  8. 操作系统(3) -- 内存管理

    3.1 内存管理概念 内存管理的基本原理和要求 为什么要进行内存管理? 虽然内存容量在不断增长,但是仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主存,于是操作系统需要对内存空间进行合理的划 ...

  9. 13 操作系统第三章 内存管理 虚拟内存 请求分页管理方式 页面置换算法 页面分配策略

    文章目录 1 虚拟内存 1.1 传统存储管理方式的特征.缺点 1.2 局部性原理 1.3 虚拟内存主要特征 1.4 如何实现虚拟内存技术 1.5 虚拟内存的基本概念小结 2 请求分页管理方式 2.1 ...

最新文章

  1. 134个预训练模型、精度高达85.1%,百度视觉算法最强基石PaddleClas全新升级
  2. 人如其名(退了51CTO的群)
  3. Python入门100题 | 第063题
  4. NETBEANS_RUBYROR shortcut
  5. Fedora 17 下 Samba 服务快速设置
  6. 重磅!中国网络空间安全协会发布《2020年中国网络安全产业统计报告》
  7. 总结Android开发中必备的代码Review清单
  8. spring boot 多数据源分布式事务处理
  9. Kepware AB驱动 · 秒懂百科
  10. JAVA基础编程练习题--50道
  11. 关于如何把支持VS2015的插件BabeLua改成支持VS2017
  12. 盛格塾丨品鉴《金石录后序》
  13. java图片变成黑白代码_转:Java对图片的处理---缩放图像、图像切割、图像类型转换、彩色转为黑白...
  14. 华为交换机ntp自动校时配置
  15. python微信发送消息过于频繁_微信发送信息频率上限?
  16. Redmi首款超高性价比笔记本明日开售 售价3999元起
  17. office2013来了
  18. pdo 参数绑定中 where 子句中的错误的解决
  19. css3怎么实现筛子的效果??transform得常用属性??
  20. Apache Arrow 简介

热门文章

  1. 盘点互联网巨头奉献的十大开源安全工具
  2. dubbo2.5-spring4-mybastis3.2-springmvc4-mongodb3.4-redis3(十)之Spring MVC中使用 Swagger2 构建Restful API...
  3. python 调用 so 库 需要注意的地方
  4. python paramiko 问题总结
  5. IT民工——全世界最齐全的条形码库!包括Code128/Code93/Code39/EAN13等22种条形码
  6. Eclipse导入import sun.misc.BASE64Decoder报错的解决办法
  7. win7+centos7.2双系统安装
  8. JAVA Spring Cloud 注册中心 Eureka 相关配置
  9. 蓝牙stack bluez学习(1)Stack Architecture
  10. CriminalIntent项目开发--后篇