操作系统-6-内存

文章目录

内存

一、内存的基础知识

在这里插入图片描述

内存是用于存放数据的硬件,程序执行前需要先放入内存中才能被CPU处理

思考:

  • 在多道程序环境下,系统中会有多个程序并发执行,也就是说会有多个程序的数据需要同时放在内存中,那么如何区别各个程序的数据放在什么地方的呢?

方案:给内存的存储单元编地址。
每个内存地址都对应一个存储单元。

在这里插入图片描述

一台手机/电脑的内存有4G,是什么意思?

  • 指的是内存中可以存放4*2^30个字节,如果按照字节编址的话,也就是有 4 * 2 ^30个小房间

1、进程的知识原理–指令

在这里插入图片描述
在这里插入图片描述

CPU能识别指令,这些指令会告诉CPU去内存的哪里存/取数据,这个数据应该做什么样的处理。

在上面的例子中,指令中给出了变量X的实际存放地址(物理地址),但是实际在生成机器指令的时候并不知道进程的数据会放到什么位置,所以编译生成的指令中一般是使用逻辑地址(相对地址)

指令中的地址也可以采用这种思想,编译的时候指令只关心“相对地址”,实际放入内存中时再想办法根据起始位置得到“绝对地址”

在这里插入图片描述

装入的三种方式(逻辑地址到物理地址的转换)

1、绝对装入(编译时候就知道放到内存的哪个绝对地址)

绝对装入:在编译的时候,如果知道程序将放入内存中的哪个位置,编译程序将产生绝对地址的目标代码。装入程序按照装入模块的地址,将程序和数据装入内存。

2、静态重定位(根据起始位置计算,装入内存时,必须分配其要求的全部内存空间)

静态重定位:又称为可重定位装入,编译、链接之后的装入模块的地址都是从0开始的,指令中使用的地址、数据存放的地址都是相对于起始地址而言的逻辑地址。可以根据内存的当前情况,将装入模块存放到合适的位置,装入时对地址进行重定位。

在这里插入图片描述

特点:作业在装入内存的时候,必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入作业,作业一旦装入内存后,在运行期间不能再移动,也不能在申请内存空间。

3、动态重定位(地址转换推迟到指令真正要执行时才进行)

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

在这里插入图片描述

二、内存管理

  • 操作系统负责内存空间的分配和回收。
  • 操作系统需要提供某种技术从逻辑上对内存空间进行扩充
  • 操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换
  • 操作系统需要提供内存保护,保证各进程在各自存储空间中运行,互不干扰。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结

在这里插入图片描述

三、覆盖技术(不常用的段在需要时调入内存)

用来解决程序大小超过物理内存总和的问题
覆盖技术的思想,将程序分为多个段(多个模块),常用的段常驻内存,不常用的段在需要的时候调入内存

常用的段放在“固定区”,调入内存就不再调出。不常用的段放在覆盖区,需要用的时候调入内存,用不到的时候调出内存。

在这里插入图片描述

四、交换技术(把暂时不运行进程对应内存中的一些数据换出到外存)

内存空间紧张的时候,系统将内存中某些进程暂时换出外存,把外存中具有运行条件的进程换入内存(进程在内存和磁盘之间动态调度)

被换出的进程数据存在对换区。对换区主要追求换入换出的速度,文件区追求磁盘利用率/

在这里插入图片描述
在这里插入图片描述

总结

在这里插入图片描述

五、内存空间的分配和回收

在这里插入图片描述

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

1、单一连续分配(内存中只有一道用户程序)

单一连续分配方式中,内存被分为系统区和用户区
系统区通常位于内存的低地址部分,用于存放操作系统相关数据,用户区用于存放用户进程相关数据。

内存中只能有一道用户程序,用户程序独占整个用户区空间。

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

2、固定分区分配(用户空间划分为若干固定大小的分区)

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

固定分区分配:

  • 分区大小相等
  • 分区大小不想等

在这里插入图片描述
分区大小相等:缺乏灵活性,但是适用于一台计算机控制多个相同对象的场合。

操作系统建立了一个数据结构–分区说明表,来实现各个分区的分配与回收,每个表项对于一个分区,通常按分区大小排列,每个表项对应分区的大小、起始地址、状态(是否已分配)。
在这里插入图片描述
优点:实现简单,无外部碎片
缺点:

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

3、动态分区分配(进程装入时,根据进程大小动态建立分区)

这种分配方式不会划分内存分区,而是在进程装入内存的时候,根据进程的大小动态建立分区。

动态分区的三个问题?

  • 1、系统会用什么样的数据结构记录内存的使用情况?
    空闲分区表或者空闲分区链
    在这里插入图片描述
  • 2、当很多空闲分区都能满足需求的时候,应该选择哪个分区进行分配?
    使用动态分配算法(下面会讲)
  • 3、如何进行分区的分配和回收操作?
    再进行分区回收的时候,如果发现有一些分区是相邻的,需要把相邻分区合并。

内部碎片和外部碎片:

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

总结

在这里插入图片描述

六、动态分区分配算法

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

有四种算法:

  • 首次适应算法
  • 最佳适应算法
  • 最坏适应算法
  • 邻近适应算法

1、首次适应算法(顺序查找找到大小能满足要求的第一个空闲分区)

算法思想:

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

如何实现:

  • 空闲分区以地址递增的次序排列,每次可以顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区

在这里插入图片描述

2、最佳适应算法

优先适应更小的分区。

如何实现:

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

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

3、最坏适应算法

算法思想:空闲分区按照容量递减的次序进行排列,每次·分配内存时按顺序查找空闲分区链(或者空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点

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

4、邻近适应算法(每次从上一次查找结束的位置开始往后查找)

每次从上一次查找结束的位置开始往后查找,找到大小能满足要求的第一个空闲分区。

在这里插入图片描述

总结

在这里插入图片描述

七、基本分页存储管理

考虑支持多道程序的两种连续分配方式:

  • 1、固定分区分配:缺乏灵活性,会产生大量的内部碎片,内存的利用率低/
  • 2、动态分区分配:会产生很多的外部碎片,虽然可以用紧凑技术来处理,但是时间代价很高。

因为连续分配算法要求进程占用一整段连续内存区域。

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

  • 不连续分配:为用户进程分配的可以是一个不连续的内存空间

分页管理的基本概念

将内存分为一个个大小相等的分区,每个分区就是一个”页框“,或者叫“页帧”、“内存块”、“物理块”。每个页框有一个编号,即“页框号”或者“内存块号”、“页帧号”、“物理块号”,页框号从0开始

将用户进程的地址空间也分为与页框大小相等的一个个区域,称为==“页”或者“页面”==,每个页面有一个编号,即“页号”,页号从0开始。

分页之后如何实现地址转换?

将进程地址空间分页之后,操作系统该如何实现逻辑地址到物理地址的转换?

重定位寄存器存放装入模块存放的起始位置。

最后存放的物理地址等于模块在内存中的“起始地址”+目标内存单元相对于起始位置的“偏移量”
在这里插入图片描述

使用了分页技术之后:
在这里插入图片描述
在这里插入图片描述
逻辑地址50对应的物理地址为450,80即偏移量为30,对应的物理地址为450+30=480

步骤:

  • 1、算出逻辑地址对应的页号
    页号 = 逻辑地址/页面长度(取除法的整数部分)
    比如上面的例子 页号 = 80/50 = 1
  • 2、要知道页号对应页面在内存中的起始地址。
  • 3、算出逻辑地址在页面内的偏移量,比如上面的逻辑地址80在页面内的偏移量为30.
    页内偏移量 = 逻辑地址 % 页面长度(取除法的余数部分)
    80 % 50 = 30
  • 4、物理地址 = 页面起始+页内偏移量

如果一个页的大小为2的12次方即4kb
在这里插入图片描述

页表

为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建议一张页表。

在这里插入图片描述

之所以说页号是隐藏的是因为页号可以通过页表的起始地址和页表长度计算出现,比如下面表示页表项需要三字节。
在这里插入图片描述

回顾

在这里插入图片描述

八、基本地址变换机构

基本地址变化机构可以借助进程的页表将逻辑地址转变为物理地址。

通常会在系统中设置一个页表寄存器,存放页表在内存中的起始地址F和页表长度M

在这里插入图片描述

设页面大小为L,逻辑地址A到物理地址E的变换过程如下:

  • 1、计算页号P和页内偏移量W(如果用十进制数手算,则P = A/L,W = A%L,但是在计算机实际运行的时候,逻辑地址结构是固定不变的,因此计算机硬件可以更快的得到二进制表示的页号、页内偏移量。)
  • 2、比较页号与页表长度M,如果P>=M,则产生越界中断,否则继续执行。(注意:页号是从0开始的,而页表长度至少是1,因此P=M时也会越界)
  • 3、页表中页号P对应的页表项地址 = 页表起始地址F+页号P*页表项长度,取出该页表项内容b即为内存块号。页表项长度表示每个页表项占多大的存储空间页表长度指的是页表中总共有多少页表项
  • 4、计算E=b*L+W,用得到的物理地址E去访存。(如果内存块号、页面偏移量是用二进制表示的,那么把二者拼接起来就是最终的物理地址了)

在这里插入图片描述

基于块表的地址变换结构

在这里插入图片描述

在这里插入图片描述

总结

在这里插入图片描述

在这里插入图片描述

两级页表

某计算机系统按自己寻址,支持32位的逻辑地址,采用分页存储管理,页面大小位4kb,页表项长度为4B。

4KB=2^12B,因此页内地址要用12位表示,剩余20位表示页号。

因此,最多有2 ^ 20页,相应的,一个进程的页表中,最多有2^20 = 1M = 1048576个页表项,所以页表需要 2 ^ 20 *4B=2 ^ 22B,并需要2 ^ 22/2 ^ 12 = 2 ^ 10个页框存储该页表。

存在的问题:

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

在这里插入图片描述

九、虚拟内存

在这里插入图片描述在这里插入图片描述

传统存储管理方式的缺点:

  • 作业一次性装入内存后才能运行。

会造成两个问题:

  • 1、作业很大的时候,不能全部装入内存,导致大作业无法运行。
  • 2、当大量作业要求运行的时候,由于内存无法容纳所有的作业,因此只有少量作业能运行,导致多道程序并发度下降。

驻留性:一旦作业被装入内存,就会一直驻留在内存中,直到作业运行结束。实际上,在一个时间段内,只需要访问作业的一小部分数据即可正常运行,这就导致了内存中会驻留大量的、暂时用不到的数据、浪费了宝贵的内存资源。

局部性原理

时间局部性

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

空间局部性

  • 一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很可能被访问。(因为很多数据在内存中是连续存放的,并且程序的指令也是顺序存放在内存中的)

高速缓存技术的思想

  • 将近期被频繁访问到的数据放到更高速的存储器中,暂时用不到的数据放在更低速的存储器中。

在这里插入图片描述

  • ==基于局部性原理,在程序装入的时候,可以将程序中很快用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行。 ==
  • 在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。
  • 若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。
  • 在操作系统的管理下,在用户看来似乎有一个比实际内存大的多的内存,这就是虚拟内存/

交换换的是进程?虚拟内存换的是内存中的页等?

虚拟内存有以下三个主要特征:

  • 多次性
    无需在作业运行时,一次性全部装入内存,而是允许分成多次调入内存。
  • 对换性
    在作业运行的时候无需一直常驻内存,而是允许在运行过程中,将作业换入、换出
  • 虚拟性
    从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际的容量

在这里插入图片描述

总结

在这里插入图片描述

十、请求分页管理方式

请求分页管理方式是在基本分页存储管理的基础上进行扩展,进而实现了的一种虚拟内存管理技术
要实现请求分页管理方式,操作系统要新增一些基本的功能:

  • 1、请求调页的功能,系统需要判断一个页面是否已经调入内存,如果没有,将页面从外存调入内存。
  • 2、页面置换:当内存暂时不够用时,需要判断将哪些页面换入到外存。

在这里插入图片描述

1、页表机制

在这里插入图片描述

2、缺页中断机构

在这里插入图片描述

在请求分页系统中,每当要访问的页面不在内存时 (比如状态位为0),便产生了一个缺页中断,然后由操作系统的缺页中断处理程序处理中断。

此时缺页的进程阻塞,放入阻塞队列,等到调页完成后将其唤醒,放回就绪队列

缺页发生时候的处理

  • 如果在缺页的时候,内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中相应的页表项。
  • 如果没有空闲块,则由页面置换算法选择一个页面淘汰,若该页在内存期间被修改过,则要将其写回外存,未修改过的页面不用写回外存。

缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,属于内中断。

在这里插入图片描述

3、地址变换机构

请求分页存储管理与基本分页存储管理的主要区别:

  • 程序在执行过程中,当锁访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后执行程序
  • 如果内存空间不够,由操作系统负责将被内存中暂时用不到的信息换出到外存。

在这里插入图片描述

总结

在这里插入图片描述

页面置换算法

页面置换算法决定了当内存空间不足的时候,操作系统需要将哪些暂时用不到的页面换出到外存

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

页面置换算法

  • 1、最佳置换算法(OPT)
  • 2、先进先出置换算法(FIFO)
  • 3、最近最久未使用置换算法(LRU)
  • 4、时钟置换算法(CLOCK)
  • 5、改进型的时钟置换算法

1、最佳置换算法(OPT,选择最长时间内不再被访问的页面)

最佳置换算法

  • 每次选择淘汰的页面将是以后永不使用,或者最长时间内不再被访问的页面,这样可以保证最低的缺页率。

例子:
假设系统为某进程分配了三个内存块,并考虑到有以下页面号引用串(会依次访问这些页面),7、0、1、2、0、3、0、4、2、3、0、3、2、1、2、0、1、7、0、1

在这里插入图片描述

整个过程缺页中断发生了9次,页面置换发生了6次(因为前面三次内存中还有空闲内存块)。

缺页时,未必发生页面置换。若还有可用空闲内存块,就不用进行页面置换。

缺页率 = 9/20 = 0.45

最佳置换算法每次选择淘汰的页面将是以后永不使用或者在最长时间不再被使用的页面,这样可以保证最低的缺页率。

最佳置换算法可以保证最低的缺页率,但是实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预判页面访问序列。因此,最佳置换算法是无法实现的

2、先进先出置换算法(FIFO)

淘汰的页面是最早进入内存的页面。

实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头的页面即可。

例:假设系统为某进程分配了四个内存块,并考虑有以下页面号引用串:
3、2、1、0、3、2、4、3、2、1、0、4

在这里插入图片描述

分配四个内存快的时候缺页次数为10次、分配三个内存快的时候缺页次数为9次。

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

FIFO实现简单,性能比较差。

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

每次淘汰的页面是最近最久未使用的页面。

实现方法:赋予一个页面对应的页表项中,用访问字段记录该页面自上次被访问以来所经历的时间t。

当要淘汰一个页面的时候,选择现有页面中t值最大的,即最近最久未使用的页面。

在这里插入图片描述
在手动做题的时候,如果需要淘汰页面,可以逆向检查此时内存中的几个页面号,在逆向扫描过程中最后一个出现的页号就是要淘汰的页面。

4、时钟置换算法(CLOCK,最近未使用算法)

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

简单的CLOCK算法实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。

当某页被访问的时候,其访问位置为1,当需要淘汰一个页面的时候,只需要检查页的访问位置,如果是0,就该悬着该页换出,如果为1,则将它置换为0,暂不换出。

在这里插入图片描述

5、改进型的时钟置换算法(优先淘汰没有被修改过的页面,因为不需要写回外存)

简单的时钟置换算法仅仅考虑一个页面最近是否被访问过,事实上,如果被淘汰的页面没有被修改过,就不需要IO操作协会外存,只有被淘汰的页面被修改过的时候,才需要写回外存。

避免IO操作,这就是改进型时钟置换算法的思想,修改为=0,表示页面没有被修改过,修改位=1,表示页面被修改过

为方便讨论,用(访问位,修改位)的形式表示各页面状态,如(1,1)表示一个页面近期被访问过,且被修改过。

在这里插入图片描述

页面分配策略

驻留集:指的是请求分页存储管理中给进程分配的物理块的集合。

驻留集太小,导致缺页频繁。驻留集太大会导致多道程序的并发度下降,资源利用率降低,所以应该选择一个合适的驻留集大小。

驻留集大小的分配

  • 1、固定分配
    操作系统为每个进程分配一组固定数目的物理块,在进程运行期间不再改变,即驻留集大小不变。
  • 2、可变分配
    先为每个进程分配一定数目的物理块,在进程运行期间,可根据情况做适当的增加或者减少,即驻留级大小可变。

置换范围:

  • 局部置换:
    发生缺页的时候只能选择进程自己的物理块进行置换
  • 全局置换
    可以将操作系统保留的空闲物理块分配给缺页进程,也可以为别的进程持有的物理块置换到外存,再分配给缺页进程。

在这里插入图片描述

1、固定分配局部置换

系统为每个进程分配一定数量的物理块,在整个运行期间都不改变,若进程在运行中发生了缺页,则只能从该进程在内存中的页面中选出一页换出,然后再调入需要的页面,这种策略的缺点是:很难在一开始就确定应该为进程分配多少个物理块才算合理。

2、可变分配全局置换

开始会为每个进程分配一定数量的物理块,操作系统会保持一个空闲物理块队列,当某进程发生缺页的时候,从空闲块中找出一块分配给该进程。如果无空闲物理块,可选择一个未锁定的页面换出,再将该物理块分配给缺页进程。采用这种策略的时候,只要某进程发生了缺页,都将获得新的物理块,仅当空闲物理块用完的时候,系统才选择一个未锁定的页面调出,被选择调出的页面可能是系统中任何一个进程的页,因此这个被选中的进程拥有的物理块会减少,缺页率会增加

3、可变分配局部置换

刚开始为每个进程分配一定数量的物理块,当某进程发生缺页的时候,只允许从该进程自己的物理块中选出一个进行换出外存,如果进程在运行中频繁的发生缺页,系统会为该进程多分配几个物理块,直到该进程缺页率适当,反之,如果进程在运行中缺页率特别的低,则可以适当减少分配给该进程的物理块。

可变分配全局置换:只要缺页就给分配新物理块
可变分配局部置换:要根据缺页的频率动态增加或减少进程的物理块。

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章