3 内存管理

3.1 内存

什么是内存,有何作用

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

思考:在多道程序环境下,系统中会有多个程序并发执行,也就 是说会有多个程序的数据需要同时放到内存中。那么,如何区分 各个程序的数据是放在什么地方的呢?方案:给内存的存储单元编地址

每个小房间就是一个存储单元。

内存管理

  • 内存空间的分配与回收
    • 连续分配管理方式
      • 单一连续分配
      • 固定分区分配
      • 动态分区分配
    • 非连续分配管理方式
      • 基本分页存储管理
      • 基本分段存储管理
      • 段页式存储管理
  • 内存空间的扩充
    • 覆盖技术
    • 交换技术
    • 虚拟存储技术
  • 地址转换
  • 存储保护

连续分配:为用户进程分配的必须是一个连续的内存空间。

非连续分配:为用户进程分配的可以是一些分散的内存空间。

地址转换

操作系统负责实现逻辑地址到物理地址的转换

三种方式:

  • 绝对装入-单道程序阶段,还没有操作系统
  • 可重定位装入-装入的时候就转换为物理地址,早期多道批处理操作系统
  • 动态运行时装入-运行时候才转换为物理地址

内存保护

内存保护可采取两种方法:

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

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

覆盖与交换

覆盖技术

早期的计算机内存很小,比如 IBM 推出的第一台PC机最大只支持 1MB 大 小的内存。因此经常会出现内存大小不够的情况。后来人们引入了覆盖技术,用来解决“程序大小超过物理内存总和”的问题

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

按照自身逻辑结构,让那些不可 能同时被访问的程序段共享同一 个覆盖区

必须由程序员声明覆盖结构,操作系统完成自动覆盖。

缺点:对用户不透明,增加了用户编程负担。 覆盖技术只用于早期的操作系统中,现在已成为历史。

交换技术

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

中级调度(内存调度),就是要决定将哪个处于挂起状态的进程重新调入内存。

  1. 应该在外存(磁盘)的什么位置保存被换出的进程?
  2. 什么时候应该交换?
  3. 应该换出哪些进程?

答:

  1. 具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。文件 区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区采用连续分配方式。总之,对换区的I/O速度比文件区的更快。
  2. 交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。例如:在 发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程; 如果缺页率明显下降,就可以暂停换出。
  3. 可优先换出阻塞进程;可换出优先级低的进程;为了防止优先级低的进程在被调 入内存后很快又被换出,有的系统还会考虑进程在内存的驻留时间… (注意:PCB 会常驻内存,不会被换出外存)

覆盖与交换的区别

覆盖是在同一个程序或进程中的

交换是在不同进程(或作业)之间的

连续分配管理方式

单一连续分配

连续分配:指为用户进程分配的必须是一个连续的内存空间

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

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

缺点:只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低。

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

固定分区分配

20世纪60年代出现了支持多道程序的系统,为了能在内 存中装入多道程序,且这些程序之间又不会相互干扰, 于是将整个用户空间划分为若干个固定大小的分区,在 每个分区中只装入一道作业,这样就形成了最早的、最 简单的一种可运行多道程序的内存管理方式。

分区大小相等:缺乏灵活性,但是很适合用于用一台计 算机控制多个相同对象的场合(比如:钢铁厂有n个相 同的炼钢炉,就可把内存分为n个大小相等的区域存放 n个炼钢炉控制程序)

分区大小不等:增加了灵活性,可以满足不同大小的进 程需求。根据常在系统中运行的作业大小情况进行划分 (比如:划分多个小分区、适量中等分区、少量大分区)

操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分配与回收。当某用户程序要装入内存时,由操作系统内核程序根据用户程序大小检索该表, 从中找到一个能满足大小的、未分配的分区,将之分配给该程序,然后修改状 态为“已分配”。 用数据结构 的数组(或 链表)即可 表示这个表

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

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

动态分区分配

动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时, 根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数 目是可变的。

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

空闲分区表、空闲分区链

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

应该用最大的分区进行分配?还是用最小的分区进 行分配?又或是用地址最低的部分进行分配? 把一个新作业装入内存时,须按照一定的动态分区分配算法,从空闲分 区表(或空闲分区链)中选出一个分区分配给该作业。 下个小节会介绍四种动态分区分配算法…

  1. 如何进行分区的分配与回收操作? 假设系统采用的数据结构是“空闲分区表”... 如何分配?
  • 若分配,则删除一个表项
  • 回收区的前、后有相邻的空闲分区,相邻的空闲分区合并为一个
  • 回收区的前、后都没有相邻的空闲分区,则新增一个表项

动态分区分配没有内部碎片,但是有外部碎片。

如果内存中空闲空间的总和本来可以满足某进程的要求,但由于进程需要的是一整块连续的内存空间,因此这些“碎片”不能满足进程的需求。可以通过紧凑(拼凑,Compaction)技术来解决外部碎片。

动态分区分配算法

动态分区分配算法:在动态分区分配方式中, 当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配?

  • 首次适应算法(First Fit)
  • 最佳适应算法(Best Fit)
  • 最坏适应算法(Worst Fit)
  • 邻近适应算法(Next Fit)

首次适应算法

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

最佳适应算法

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

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

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

最坏适应算法( 最大适应算法)

算法思想:在每次分配时 优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。

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

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

邻近适应算法

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

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

首次适应算法每次都要从头查找,每次都需要检索低地址的小分区。 但是这种规则也决定了当低地址部分有更小的分区可以满足需求时, 会更有可能用到低地址部分的小分区,也会更有可能把高地址部分的 大分区保留下来(最佳适应算法的优点) 邻近适应算法的规则可能会导致无论低地址、高地址部分的空闲分区 都有相同的概率被使用,也就导致了高地址部分的大分区更可能被使 用,划分为小分区,最后导致无大分区可用(最大适应算法的缺点)

综合来看,四种算法中,首次适应算法的效果反而更好

非连续分配管理方式

连续分配:为用户进程分配的必须是一个连续的内存空间。

非连续分配:为用户进程分配的可以是一些分散的内存空间。

基本分页存储管理

分页存储:

  • 将内存空间分为一个个大小相等的分区,每个分区就是一个“页框”(页框=页帧=内存块=物理块=物理页面)。每个页框有一个编号,即“页框号”,从0开始。
  • 将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个“页”或“页面” 。每个页面也有一个编号,即“页号”,页号也是从0开始。

(注:进程的最后一个页面可能没有一个页框那么大。也就是说,分页存储有可能产生内部碎片,因此页框不能太大,否则可能产生过大的内部碎片造成浪费)

操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,可以放到不相邻的各个页框中。

重要的数据结构——页表

问题一:每个页表项占多少字节?

Eg:假设某系统物理内存大小为 4GB,页面大小为 4KB,则每个页表项至少应该为多少字节?

内存块大小=页面大小=4KB= 2^12 B

4GB 的内存总共会被分为 2^32 / 2^12 = 2^20个内存块

内存块号至少要用 20 bit 来表示

至少要用3B来表示块号(3*8=24bit)

注意:页表记录的只是内存块号,而不 是内存块的起始地址! J 号内存块的起始地址 = J * 内存块大小

问题二:如何实现逻辑地址到物理地址的转换的?

特点:虽然进程的各个页面是离散存放的,但是页面内部是连续存放的
如果要访问逻辑地址 A,则
①确定逻辑地址A 对应的“页号”P
②找到P号页面在内存中的起始地址(需要查页表)
③确定逻辑地址A 的“页内偏移量”W
逻辑地址A 对应的物理地址 = P号页面在内存中的起始地址+页内偏移量W

那么,如何确定一个逻辑地址对应的页号、页内偏移量?

Eg:在某计算机系统中,页面大小是50B。某进程逻辑地址空间大小为200B,则逻辑地址 110 对应 的页号、页内偏移量是多少?

基本分段存储管理

段页式存储管理

页面置换算法

  • 最佳置换算法(OPT)
  • 先进先出置换算法(FIFO)
  • 最近最久未使用置换算法(LRU)
  • 时钟置换算法(CLOCK)

请求分页存储管理与基本分页存储管理的主要区别: 在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。 若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存

页面的换入、换出需要磁盘 I/O,会有较大的开销,因 此好的页面置换算法应该追求更少的缺页率

最佳置换算法(OPT)

选择淘汰的页面将是以后永不使用,未来很长时间不使用的,即找最后一个出现的那个替换掉

最佳置换算法可以保证最低的缺页率,但无法实现。

先进先出置换算法(FIFO)

每次选择淘汰的页面是最早进入内存的页面

Belady 异常——当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。 只有 FIFO 算法会产生 Belady 异常。

另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,算法性能差

最近最久未使用置换算法(LRU)

淘汰上一次使用时间距离现在最久的那个。

该算法的实现需要专门的硬件支持,虽然算法性能好,是最接近OPT算法性能的 ,但是实现困难,开销大

时钟置换算法(CLOCK)

时钟置换算法是一种性能和开销较均衡的算法,又称CLOCK算法,或最近未用算法(NRU,Not Recently Used)

从那些最近一个时期内未被访问的页中任选一页淘汰。【R(读)与M(修改)位都为0的那个】

实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成 一个循环队列。当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需检查页的访问位。 如果是0,就选择该页换出;如果是1,则将它置为0,暂不换出,继续检查下一个页面,若第一轮扫 描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描

(第二轮扫描中一定会 有访问位为0的页面,因此简单的CLOCK 算法选择一个淘汰页面最多会经过两轮扫描)

例题

1、在引入快表的分页存储管理方式中,如果访问主存时间为100ns,访问快表时间为30ns,命中率为80%,则内存的有效访问时间为多少?( 150 )

(30+100)x0.8 + (30+100+100)x0.2 =150

posted @   Dinesaw  阅读(253)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示