操作系统笔记 P03:内存管理

1. 内存管理的概念

内存管理的功能:

  • 内存空间的分配与回收
  • 地址转换:将逻辑地址转换成物理地址
  • 内存空间的扩充:从逻辑上扩充内存
  • 存储保护:保证各道程序在各自的存储空间运行,互补干扰

程序装入和链接

源程序变为内存中可执行的程序,需要以下几个步骤:编译、链接、装入。编译形成目标模块,链接形成装入模块。

程序的链接有三种方式:

  • 静态链接:程序运行前,先将各目标模块和其所需库函数链接成一个完整的可执行程序,不再拆开。
  • 装入时动态链接:目标模块在装入内存时,边装入边链接。
  • 运行时动态链接:在程序执行到该目标模块时才对它进行链接。其优点是便于修改和更新,便于实现对目标模块的共享。

装入模块装入内存有三种方式:

  • 绝对装入:编译时已经确定程序在内存中的位置,编译产生的代码中的地址为绝对地址,不需要对地址进行转换。只适用于单道程序环境中。

  • 可重定位装入:多道程序环境中,目标模块的起始地址多是从 0 开始的,此时程序中的地址都是相对地址。装入程序根据内存的当前状况,将装入模块装入内存的合适位置,其中的地址将全部修改为绝对地址。修改地址的过程称为重定位,这种方式又称静态重定位。

    这种方式下装入一个程序时必须分配其要求的全部内存空间,并且装入后无法移动位置,也不能再申请空间。

  • 动态运行时装入:又称动态重定位。装入程序把装入模块装入内存时并不立即修改地址,而是在程序真正要执行时才进行相对地址到绝对地址的转换。

    这种方式下可以将程序分配到不连续的内存空间中;在程序运行之前可以只装入其部分代码即可投入运行,运行期间程序可根据需要申请新的内存。

逻辑地址空间和物理地址空间

编译后每个模块都是从 0 开始编址,称为目标模块的相对地址/逻辑地址。程序员只需要直到逻辑地址即可。

内存中的实际地址称为绝对地址/物理地址。将逻辑地址转换为物理地址,称为地址重定位。

内存保护

内存分配前,需要保护操作系统不受用户进程的影响,用户进程之间也不能相互影响。需要内存保护,有两种方法:

  • 在 CPU 中设置一对上下限寄存器,存放用户作业在主存中的上下限地址。每当 CPU 访问一个地址时,与两个寄存器中的地址比对,判断是否越界。
  • 采用重定位寄存器(或基址寄存器)和界地址寄存器(或称限长寄存器),重定位寄存器中存有用户作业的最小的物理地址,界地址寄存器中存有用户作业的最大的逻辑地址。每个逻辑地址必小于界地址寄存器的值,否则发生越界。未发生越界的逻辑地址加上重定位寄存器的值,就是该逻辑地址对应的物理地址,再将此物理地址提交给内存即可。

覆盖与交换

覆盖与交换技术是多道程序环境下用来扩充内存的方法。交换技术用于不同进程之间,而覆盖技术则用于同一个程序或进程中。现代操作系统通过虚拟内存技术替代了覆盖技术,而交换技术仍在使用。

覆盖

将用户空间分成一个固定区和若干个覆盖区,将活跃的部分放在固定区,其余部分按调用关系分段,将即将访问的段放入覆盖区,其余段放在外存。在某段需要被调用前,在将其调入覆盖区,替换覆盖区中的原有的段。

覆盖技术的特点是打破了必须将一个进程的全部信息装入主存后才能运行的限制。

交换

交换是将处于等待状态的程序从内存移到外存,腾出内存空间,称为换出;将准备好竞争 CPU 的程序从外存移到内存,称为换入。

2. 连续分配管理方式

单一连续分配

此方式下内存分为系统区和用户区,系统区供操作系统使用,通常在地址低位;用户区是除系统区之外的内存空间。这种方式内存中只有一道程序,无需内存保护。

  • 优点是简单、无外部碎片,可以采用覆盖技术。
  • 缺点是只能用于单用户单任务的操作系统中,有内部碎片,存储器利用率极低。

固定分区分配

此方式下用户内存被划分成若干个固定大小的区域,每个分区只装入一道作业,当有空闲分区时便从外存的后备作业队列中选择适当大小的作业装入分区。

  • 分区大小相等
  • 分区大小不等划分为多个较小的分区,适量中等的分区和少量大分区。

为了便于内存分配,通常将分区按大小排队,并建立一个分区说明表,每一个表项包括每个分区的起始地址、大小及状态(是否已分配)。

固定分区分配这种方式为最简单的多道程序存储分配,无外部碎片。但是有时可能程序太大而无法放入一个分区,需要使用覆盖技术;固定的分区大小会造成内部碎片,浪费内存空间。引出此方式下的存储空间利用率低。

动态分区分配

动态分区分配又称可变分区分配。这种方式下是在进程装入内存时,根据进程大小动态建立分区,使分区的大小适合进程的需要。对空闲内存的跟踪,可以使用位图来标记没有分配的内存单元,或者使用链表将空闲的内存块链接起来。

动态分区分配在开始时会很好地利用内存,但是之后会导致小的内存碎片。随着进程的不断换入换出,碎片越来越多,内存的利用率下降。解决此问题可以通过紧凑技术,即操作系统对进程进程移动和整理,消除碎片。

动态分区的分配策略

当进程装入或换入内存时,操作系统需要决定分配哪个内存块给进程。主要有以下算法:

  • 首次适应算法:空闲分区按照地址递增的顺序排列,分配内存时按顺序查找,找到第一个大小能满足进程的空闲分区,分配给进程使用。
  • 最佳适应算法:空闲分区按照容量递增的顺序排列,分配内存时按顺序查找,找到第一个大小能满足进程的空闲分区,分配给进程使用。也即挑出满足要求且最小的空闲分区。
  • 最坏适应算法:空闲分区按照容量递减的顺序排列,分配内存时按顺序查找,找到第一个大小能满足进程的空闲分区,分配给进程使用。也即挑出满足要求且最大的空闲分区。又称最大适应算法。
  • 邻近适应算法:在首次适应算法的基础上,查找时从上一次查找结束的地方开始。又称循环首次适应算法。

首次适应算法是最好的,而最佳适应算法性能通常很差,最坏适应算法性能最坏。

3. 非连续分配管理方式

抖动/颠簸是指刚刚换出的页面马上又换入主存,刚刚换入的页面马上又换出主存。发生抖动时会大大降低系统的效率。

工作集/驻留集是指某段时间内,进程要访问的页面集合。为防止抖动现象,需要选择合适的工作集大小。操作系统需要跟踪每个进程的工作集,并为进程分配大于其工作集的物理块数;若还有空闲物理块,则再调入一个进程到内存;若所有工作集之和大于可以物理块数,则操作系统会暂停一个进程,防止抖动。

基本分页存储管理方式(一维)

分页存储管理的思想是:把主存空间划分成大小相等的块,一般大小为 2 的整数幂。块相对较小,作为主存的基本单位。每个进程也已块为单位进行划分,进程在执行时已块为单位逐个申请主存中的空间。分页管理不会产生外部碎片,每个进程平均产生半个块大小的内部碎片,内存利用率高。

进程中的块称为页,内存中的块称为页框,外存也以同样的大小划分,直接称为块。取页的大小为 4KB,分页后的逻辑地址可以分为两部分:页号 P 和页内偏移量 W,页号为 12~31 位,页内偏移量(页内地址)为 0~11 位。

为了便于内存中找到进程每个页对应的物理块,系统为每个进程建立了一张页表。页表存储在内存中,每个页表项包含两个部分:页号和页号对应的物理块号。页表实现了页号到物理块号的地址映射,转换时将逻辑地址的页号换成物理块号即可转换为物理地址。

基本地址转换机构

系统中通常设置一个页表寄存器 PTR,用于存放页表在内存中的起始地址和页表长度。进程未执行时,页表起始地址和页表长度都保存在进程控制块 PCB 中,进程执行时,两项内容存入 PTR。设页面大小为 L,逻辑地址 A 到物理地址 E 的转换过程如下:

  1. 计算逻辑地址对应的页号 P = A / L 和页内偏移量 W = A % L,也即将逻辑地址分成两部分;
  2. 比较页号 P 和页表长度 M(两个都是偏移量),若 P 大于等于 M,则发生越界中断,否则继续执行;
  3. 查找页号 P 对应的物理块号 b。b = 页表起始地址(也是第 0 页对应的块号) + 页号 P * 每页包含的物理块数;
  4. 计算物理地址 E = b * L + W。

该过程由硬件自动完成。

注意:如果以 4KB 为页的大小,则 32 位地址中有 20 位可以作为页号,共 1M 页,那么每个页表项的长度最少为 3B = 24 > 20。页表也是存放在页中的,取页表项长度为 4B,则每个页中可以存放 1K 个页表项,仍需要 1K 页用于存放页表。

如果地址转换的过程不够快,则访存速度必然降低;如果页表过大,占用了过多的页,则内存的利用率降低。

具有快表的地址转换机构

在地址转换机构中增设一个快表 TLB,又称联想寄存器。快表是一个具有并行查找能力的高速缓冲存储器,用来存放当前访问的若干页表项,根据程序访问的局部性原理,加速地址转换的过程,一般 TLB 的命中率达 90%以上。相对的内存中的页表也被称为慢表。

具有 TLB 的机构中,地址转换的过程如下:

  1. 由硬件将逻辑地址分开为页号和页内偏移量。页号送入高速缓存,将其与 TLB 内的页表项进行比较。
  2. 若匹配到对应的页表项,页直接从 TLB 中取出该页对应的页框号,与页内偏移量拼接成物理地址使用。
  3. 若每页匹配到,则需要访问内存中的页表,计算物理地址。同时将该页表项替换入 TLB 中。

有些处理机设计为快表和慢表同时查找,如果在快表中匹配到则停止慢表的查找。

两级页表

随着内存容量的不断增大,页表的程度也在增长。为了压缩页表,引入二级分页。规定顶级页表只能存入一个页,如上述的 4KB 的分页只能保存 1K 个页表项,顶级页表的长度不能大于 1K。此时 1K 一级页号需要 10 位地址,4KB 的分页需要 12 位存储页内偏移量,所有二级页号也是 10 位,正好可以放入一个分页。

也即两级页表方式下,32 位逻辑地址中,一级页号占用最高的 10 位, 二级页号占用中间的 10 位,页内偏移量占用最低的 12 位。

基本分段存储管理方式(二维)

分段存储管理的思想是:按照用户进程中的自然段划分逻辑空间,也即段的大小根据进程确定,不是固定的长度。但是一个程序可以根据需要分成多个段,段内连续,段间不连续。

分段后将逻辑地址分为两部分:段号 S 和段内偏移量 W。内存分页对应用户是透明的,但在段式系统中,段号和段内偏移量必须由用户提供,这个工作一般由编译器完成。

每个进程都有一个段表,包含段号、段长、本段在内存中的起始地址,用于逻辑地址到物理地址的转换。系统中设置一个段表寄存器,用于存放段表初始地址 F 和段表长度 M。进程执行时会将该进程对应的两项内容存入寄存器。

  1. 将逻辑地址分成段号和段内偏移量;
  2. 比较段号 S 和段表长度 M,若 S 大于等于 M,则产生越界中断;否则继续执行;
  3. 该段的起始物理地址 b = 段表起始地址 F + 段号 S * 每段包含的物理块数;
  4. 物理地址 E = b + W。
段的共享与保护

在分段系统中,段的共享是由两个作业的段表中相应表项指向被共享的段的同一物理副本来实现的。当一个作业正从共享的段中读取数据时,必须防止另一个作业修改此共享段中的数据。

分段管理的包含方法有两种:存取控制、地址越界保护。

段页式管理方式(二维)

在段页式系统中,作业的地址空间首先被分成若干个逻辑段,每段有自己的段号,然后将每一段分成若干个大小固定的页。对内存空间的管理仍和分页存储管理一样,以块为单位进行。

此时作业的逻辑地址分为三部分:段号 S、页号 P、页内偏移量 W。为了实现地址转换,系统为每个进程建立了一个段表,而每个分段有一张页表。注意一个进程只有一个段表,但是可以有多个页表。段表项中包括段号、页表长度、页表起始地址,页表项中包括页号和块号。在进行地址转换时,首先通过段表查到页起始地址,然后通过页表找到对应的物理块号,最后形式物理地址。

4. 虚拟内存管理

虚拟内存的概念

传统存储管理方式具有以下两个特征:作业必须一次性全部装入内存,作业装入内存后就一直驻留在内存中。很多作业运行时根本不用的程序和数据占用了大量的内存空间,浪费宝贵的内存资源。

虚拟存储器基于程序局部性原理,操作系统将内存暂时不使用的内容换出到外存中,从而腾出空间存放将要调入内存的信息。主要有以下三个特征:多次性(作业允许被分成多次调入内存)、对换性(作业运行时无需常驻内存,进行换入换出)、虚拟性(从逻辑上扩充内存,即把外存虚拟成内存的一部分)。

虚拟内存技术的实现

虚拟内存的实现需要建立在离散分配的内存管理方式基础上。主要有以下三种方式:请求分页存储管理、请求分段存储管理、请求段页式存储管理。

请求分页管理方式

实现请求分页需要一定容量的内存和外存的计算机系统,以及页表机制、缺页中断机制和地址变换机制。

页表机制

请求分页系统的页表机制不同于基本分页系统。请求分页系统在一个作业运行之前不要求全部一次性调入内存,作业运行过程中,必然会出现要访问的页不在内存的情况。

发现和解决这种页面不在内存的情况是请求分页系统必须解决的两个基本问题。为此在请求分页页表项中增加了四个字段,页表项包括:页号、物理块号、状态位 P、访问字段 A、修改位 M、外存地址。

  • 状态位 P:该页是否已调入内存。
  • 访问字段 A:该页在一段时间内被访问的次数,供置换算法参考。
  • 修改位 M:该页调入内存后是否被修改过。
  • 外存地址:该页在外存上的地址,通常是物理块号。
缺页中断机制

当访问的页不在内存中时,便产生一个缺页中断,请求操作系统将所缺的页调入内存。缺页中断的中断处理程序会查找内存是否有空闲的块,若有空闲的块,则将所缺的页装入该块;若没有空闲的块,则需要替换掉某页。

缺页中断需要在指令执行中产生和处理中断信号,属于内部中断。且一条指令的执行期间,可能会产生多次中断。

地址变换机制

请求分页系统中的地址变换过程如下:

  1. 但程序请求访问某一页时,首先判断页号是否越界,越界则产生越界中断;
  2. CPU 检索快表,如果对应页表项不在快表中,则检查慢表。
    • 如果找到了对应页表项,则通过页表项将该页的逻辑地址转换成物理地址,同时将该页表项放入快表,根据实际情况修改页表项的访问字段和修改位。
    • 如果没有找到对应的页表项,则产生缺页中断,执行缺页中断处理程序。
  3. CPU 保护现场。从外存中找到所缺的页,准备将其装入内存。
    • 如果此时内存未满,则将其直接装入内存,修改页表。
    • 如果此时内存已满,则需要进行页面替换,选择一个页面将其换出。如果换出的页面发生该修改,还需将其写回外存。
  4. 缺页中断处理结束,CPU 恢复现场,通过访问页表进程地址转换,同时将该页表项放入快表,修改页表项的访问字段和修改位等。

页面置换算法

最佳置换算法 OPT

最佳置换算法选择以后永久不会再使用或者最长时间内不再访问的页,将其换出。这种算法可以保持最低的缺页率,但是目前无法预测哪个页面在未来不会被访问,因此该算法无法实现。

先进先出 FIFO 页面置换算法

优先换出最早进入内存的页面,也即在内存中驻留时间最长的页面。

FIFO 算法会产生当所分配的物理块数(内存页框数)增大而缺页率不减反增的异常现象,称为 Belady 异常。

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

根据页表项中的访问字段,选择过去一段时间内未访问过的页面,将其换出。

LRU 性能较好, 但是需要寄存器和硬件的支持。LRU 算法不会出现 Belady 异常。

时钟 CLOCK 置换算法/最近未用 NRU 算法

简单的 CLOCK 算法为每一页增加一个使用位,当该页调入内存或者被访问时,使用位都置 1;操作系统将所有的候选替换页集合看作一个循环缓冲区,并有一个指针指向其中一页;当需要替换一页时,操作系统从指针指向的页开始,若该页使用位为 1 则将其置 0,若该页使用位为 0 则将其替换,无论何种情况,指针会指向循环缓冲区的下一页;若该循环缓冲区中的所有页的使用位都为 1,在一次循环后,起始位置的页的使用位已经变为 0,将其替换即可。

CLOCK 算法又称为最近未用算法,其性能接近 LRU。

通过增加使用位的数目可以使得 CLOCK 算法更高效,在使用位 u 的基础上增加一个修改位 m,得到改进型 CLOCK 算法。具体的操作步骤如下:

  1. 操作系统从指针指向的页开始,选择(u = 0, m = 0)的页进行替换。这次扫描过程中不修改使用位和修改位;
  2. 若上一步没有找到符合的页,则重新扫描,选择(u = 0, m = 1)的页进行替换,同时将经过的页的使用位 u 改为 0
  3. 若上一步没有找到符合的页,则跳回步骤 1。若步骤 1 仍未找到符合的页,则继续执行步骤 2,此时一定有符合的页。

改进型 CLOCK 算法优先替换未被访问过的页,如果所有的页都被访问过,则替换未被修改过的页。

页面分配策略

当操作系统给一个进程的存储量越小,则驻留在主存中的进程数越多,可以提高处理机的时间利用率。但是一个进程在主存中的页数过少,缺页率会较高;页数过多,给该进程分配更多的主存空间也不会降低缺页率。

页面的分配现代操作系统通常采用以下三种策略:

  • 固定分配局部置换:每个进程分配得的物理块数在运行过程中是不会改变的,若进程发生缺页,则从该进程的内存中替换出一页。这种策略很难确定一个进程所需的合适的物理块数目,太少会频繁缺页,太多会降低主存利用率。
  • 可变分配全局置换:为每个进程分配一定数目的物理块的同时,操作系统自身也保持一个空闲物理块队列。当某进程缺页时,系统从空闲物理块队列分配一个物理块给该进程,将需要的页装入。这种策略会盲目地为进程增加物理块,降低系统的多道程序并发能力。
  • 可变分配局部置换:为每个进程分配一定数目的物理块的同时,操作系统自身也保持一个空闲物理块队列。当某个进程缺页时,从该进程的内存中替换出一页;只有一个进程频繁缺页时,系统从空闲物理块队列中分配一块给该进程使用,直至其缺页率趋于适当程度;若一个进程的缺页率特别低是,可以适当地减少分配给该进程的物理块。
调入页面的时机
  • 预调页策略:一次调入若干个相邻的页可能比一次调入一页更加高效,前提是预测准确。目前预调页成功率越 50%,故这种策略仅用于进程首次调入内存时,由程序员指出应该先调入哪些页。
  • 请求调页策略:进程在运行中需要访问的页面不在内存中而提出要求,由系统将所需页面调入内存。目前虚拟存储器中大多使用此策略,进程运行过程中使用此策略。

两种调页策略同时使用,处于进程的不同时期。

从何处调入页面

请求分页系统的外存分为两部分:对换区和文件区。对换区采用连续分配,文件区采用离散分配,对换区的 I/O 速度比文件区快。

从何处调入页面有三种情况:

  • 系统拥有足够的对换区:全部从对换区调入所需页面。为此,进程运行前需将与该进程相关的全部文件复制到对换区。
  • 系统缺少足够的对换区:不会被修改的文件直接从文件区调入,可能修改的部分,换出时放入对换区,以后需要时再从对换区调入。
  • UNIX 方式:与进程相关的文件都在文件区,未运行过的页面,需要从文件区调入;曾经运行又被调出的页面,放入对换区,再次使用时从对换区调入。进程请求的共享页面若已被其它进程调入,则无须再从对换区调入。
posted @ 2020-07-30 16:00  ixtwuko  阅读(401)  评论(0编辑  收藏  举报