存储器管理

OS系统存储器管理的任务,就是动态实现用户区的管理,以便将尽可能多的进程装入存储器中,踢高存储器的利用率。存储器管理要实现的目标是:为用户提供方便、安全和充分大的存储空间。

存储管理应具有下列功能:

(1)分配和回收。由OS完成内存空间的分配和管理,使程序员摆脱存储空间分配的麻烦,提高编程效率。为此系统应该记住内存空间的使用情况,实施内存的分配,回收系统或应用释放的空间。

(2)抽象和映射。主存储器被抽象,使得进程认为分配给它的是地址空间。在多道程序设计系统中,地址空间中的逻辑地址和物理地址不可能一致,因此,存储管理必须将物理地址转换为虚拟地址。

(3)内存的扩充。借助覆盖技术和虚拟存储技术,为用户提供比内存空间更大的地址空间,从而实现从逻辑上实现扩大内存容量的目的。

(4)存储的保护。保护进入内存的各道作业都在自己的内存空间运行,互不干扰。既要防止一道作业由于错误而破坏其他作业,也要防止破坏系统程序。这种保护一般由硬件和软件配合完成。

存储管理的基本概念

程序的装入

在多道程序环境下,只有当先为某个程序创建进程后,该程序才能运行。创建进程,首先需要将程序和数据装入内存。将一个用户源程序变成一个可在内存中执行的程序,通常需要经过以下几步:

(1)编译。由编译程序将用户源代码编译成若干个目标模块。

(2)链接。由链接程序将编译后形成的目标模块以及它们所需的函数库链接在一起,形成一个装入模块。

扫描二维码关注公众号,回复: 59725 查看本文章

(3)装入。由装入程序将装入模块装入内存。

为了提高利用率,引入了动态装入方式,上述几个步骤往往交织在一起。

1.绝对装入方式。

在编译时如果知道程序驻留在内存的什么地方,那么编译程序将产生绝对地址的目标代码。绝对装入程序按照装入模块的地址,将程序和数据装入内存。装入模块被装入内存后,由于程序中的逻辑地址和实际内存地址相同,故不需对程序和数据进行修改。

这种装入方式的特点是:

(1)知道程序在内存中的位置,故编译时产生绝对地址。

(2)装入模块后,由于程序中的逻辑地址和实际地址完全相同,不需对程序和数据进行修改。

(3)只能将目标模块装入内存中事先指定的位置,仅适用于单道程序环境。

(4)通常在程序中采用符号地址,然后在汇编和编译时,再将这些符号地址转换为绝对地址。

2.可重定位装入方式。

一个应用程序编译后,通常会形成若干个目标模块程序,这些模块再经过链接而形成可装入执行的程序。这些程序的地址都从“0”开始编址,程序中的其他地址都相对于该地址进行计算;由这些地址形成的地址范围被称为地址空间,其中的地址称为逻辑地址。逻辑地址又称为虚地址、相对地址。存储空间也称为内存空间,是指内存中一系列存储信息的物理单元的集合,称为物理地址,又称为绝对地址和实地址。为了保证程序的正确性,需要对程序中的地址进行变换,这种将逻辑地址转换为物理地址的过程也称为地址重定位,也称为地址映射或地址变换。这种地址变换只在装入时一次完成,以后不再改变,所以称为静态重定位。静态重定位的特点是在一个作业装入内存时必须分配其所要求的全部内存空间,如果没有足够的内存空间空闲,那么就不能装入内存。作业一但装入内存后就不能在内存移动,也不能申请内存空间。

可重定位装入方式的特点

(1)装入模块的逻辑地址一般与实际装入内存的物理地址不同。

(2)实际装入内存的物理地址=逻辑地址+程序起始地址。

3.动态运行时装入方式

动态运行时装入程序,把装入模块装入内存后,并不立即把装入模块的逻辑地址转换为物理地址,而是把这种地址转换推迟到程序要真正执行时才进行。因此,装入内存后的所有地址仍为逻辑地址。为了不影响指令的执行速度,这种方法需要特殊的硬件支持,把这种地址变换方式称为动态重定位。动态重定位是指在程序执行过程中,每当访问指令或数据时,将要访问的指令或数据的逻辑地址转换为物理地址。由于重定位过程是在程序执行期间随着指令的逐步执行完成的,所以叫做动态重定位。动态重定位需要依靠硬件地址变换机构,最后简单的方法是利用一个重定位寄存器。当某个作业开始执行时OS负责把该作业在内存中的起始地址送入重定位寄存器,之后,在作业的整个执行过程中,每当访问内存时,系统自动将重定位寄存器中的内容加到逻辑地址中去,从而得到该逻辑地址对应的物理地址。动态重定位的特点是可以将程序分配到不连续的存储区中,在程序运行之前可以只装入它的部分代码即可投入运行,然后在程序运行期间再根据需要动态分配内存空间;便于程序段的共享,可以向用户提供一个比内存的存储空间大得多的地址空间。

程序的链接

实现链接的方法有三种:静态链接、装入时动态链接和运行时动态链接。

(1)静态链接方式

编译后形成目标模块后,其起始地址都是“0”,每个模块的地址都是相对于0的。在将目标模块链接成一个装入模块时,某些模块的起始地址不再是0,因此要进行修改。这种先进行链接所形成的一个完整的装入模块,称为可执行文件。静态链接是在生成可执行文件时进行的,可执行文件形成后,通常不再拆开它,要运行时可直接将它装入内存。这种事先进行连接,以后不再拆开的方式称为静态链接方式。

(2)装入时动态链接

采用装入时动态链接,用户源程序经编译后得到的目标模块,是在装入内存时边装入边链接的。即在装入一个目标模块时,若发生一个外部模块调用,则将引起装入程序去寻找相应的外部模块,并将它装入内存,同时修改目标模块中的相对地址。

装入时动态链接的优点是:(1)便于软件版本的修改和更新。(2)便于实现目标模块的共享。

3.运行时动态链接

执行过程中,当发现一个目标模块尚未被装入内存时,由OS去找到该模块,将它装入内存,并将其链接到调用者模块上,这种链接方式称为运行时动态链接。

耦合性:也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。内聚性:又称块内联系。指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。若一个模块内各元素(语名之间、程序段之间)联系的越紧密,则它的内聚性就越高。
内存保护。

在多道程序环境下OS必须提供存储保护机制,存储保护机制是为了防止一个进程有意或无意地破坏用户进程或系统进程。常用的存储保护方法有:

(1)界限保护(界限存储器)。通过对每一个进程设置一对界限存储器来防止越界访问,达到存储保护的目的。采用界限存储器实现存储保护又有两种实现方法:上、下寄存器方法和基址、限长存储器方法。用上、下界存储器分别存放进程存储空间的起始地址和结束地址。在进程运行中,将每一个访问内存的地址都同这两个寄存器的内容相比较,在正常情况下,这个地址应该大于起始地址小于结束地址。若超出了上下界存储器的范围,则产生越界中断信号哦,并停止进程的运行。用基址和现场寄存器分别存放进程空间的初始地址和进程地址的空间长度。当进程执行时访问内存的逻辑地址超出了限长,则产生越界中断信号,并停止进程的运行。

(2)访问方式保护(保护键)。通过保护键匹配来判断存储访问方式是否合法,对于允许多个进程共享的存储区域,每个进程都有自己的访问权限。存储保护键方法是给每个存储块分配一个单独的保护键,它相当于一把锁。进入系统的每个进程也赋予一个保护键,它相当于一把钥匙,查看钥匙和锁是否匹配,若不匹配,则系统发出保护性中断信号,停止进程运行。

(3)环保护。处理器状态分为多个环,分别具有不同的存储访问特权级别,通常规定环的编号越小特权级别越高。

此外还有四种存储权限:禁止任何操作、只能执行、只能读、读/写。

单一连续分配

一种最简单的存储管理方式,通常只能用于单用户、单任务的操作系统中,这种存储管理方式将内存分为两个连续存储区域,其中一个存储区域固定分配给OS使用,另一个存储区域分配给用户作业使用。单一连续内存方式主要采用静态分配,即作业一旦进入内存,就要等到它执行结束后才能释放内存。采用这种存储分配方式,内存中只能装入一道作业,从而降低了资源利用率。

分区存储管理

是满足多道程序设计需要的一种最简单的存储管理方法。在分区存储管理中,内存被划分为若干个分区,分区的大小可以相等也可以不等,除操作系统占有一个分区外,其余的每个分区可以容纳一个用户作业。按照作业的变化情况可以将分区存储管理进一步分为固定分区存储管理和动态分区存储管理。

固定分区

固定分区存储管理方法是一种可以运行多道程序的存储管理方法,它将内存事先划分为若干个固定大小的分区,分区的大小可以不等,但事先必须确定,运行时不能改变。为了实现固定分区分配,系统需要建立一张分区说明表,以记录分区的使用情况,其中包括分区号、分区大小、分区地址及状态等信息。当某个用户程序要装入内存时,由内存分配程序检索分区说明图,从图中找到一个能满足要求的空闲分区分配给该程序,然后修改分区说明图中相应表项的状态信息。当程序执行完毕,释放程序占用的分区,并将对应的分区状态信息设置为未分配即可。作业的大小不一定与某个分区大小相等。

动态分区

又称为可变分区分配,是一种动态划分存储器的分区方法,这种分配方法并不预先设置分区的数目,而是在作业装入内存时,根据作业的大小动态建立分区,使分区正好满足作业的需要。 因此分区的大小可变,数目也可变。

1.分区分配中的数据结构

系统需要设置相应的数据结构来记录内存的使用情况,常用的数据结构形式有空闲分区表和空闲分区链。

(1)空闲分区表。内存中的每个空闲分区占用一个表项,每个表项包含分区号、分区起始地址、分区大小及状态等。

(2)空闲分区链。使用链表指针将内存中的空闲区链接起来,为此应该在每个空闲分区的起始若干字节存放分区的若干字节中存放分区的相关信息,包括空闲分区的大小和指向下一个空闲分区的指针。

2.分区分配算法。为了将一个作业装入内存,应按照一定的分配算法从空闲分区表(或空闲分配链)选出一个满足作业需求的分区分配给作业,如果这个空闲分区的容量大于作业申请的空间容量,则将该分区一分为二,一部分分配给作业,剩下的一部分仍然留在空闲分区表(或空闲分配链),同时还需要对空闲分区表(或空闲分配链)中的有关信息进行修改。目前采用的分区分配算法有:首次适应算法、循环首次适应算法、最佳适应算法及最坏适应算法。

(1)首次适应算法。又称最先适应算法,该算法要求空闲分区按地址递增的次序排列。从空闲分区表(或空闲分配链)首开始顺序查找,一直查找到第一个能满足其大小要求的内存空间为止。

(2)循环首次适应算法。下次适应算法。从上次分找到的空闲分区继续向后查找到第一个满足作业申请空间的空闲分区。

(3)最佳适应算法。要求空闲分区按照容量的大小递增的次序排列,在进行内存分配时,从空闲分区表(或空闲分配链)首开始顺序查找,直到找到第一个能满足作业申请空间的空闲分区。

(4)最坏适应算法。要求按容量大小递减的次序排列,在进行内存分配时,先检查空闲分区表(或空闲分配链)的第一个分区,若第一个空闲分区小于作业要求的大小,则分配失败。否则从空闲分区划出与作业大小相等的一块内存空间分配给请求者,将余下的空闲分区留在空闲分区表(或空闲分配链)中。

分区的回收

当作业执行结束时,应回收已利用完毕的分区。系统根据回收分区的大小及起始地址在空闲分区表(或空闲分配链)中检查是否有与其相邻的空闲分区,若有相邻空闲分区,合并为一个更大的空闲区,然后修改有关分区的状态信息。

回收分区与已有空闲分区的相邻情况有以下四种:

(1)回收分区r上邻接一个空闲分区。(2)回收分区r下邻接一个分区。(3)回收分区r上、下邻接空闲分区。(4)回收分区无邻接空闲分区,这时应为回收分区单独建立一个新表项,填入分区大小及起始地址等信息,并将其加入到空闲分区表(或空闲分配链)中的适当位置。

可重定位分区分配

在分区存储管理中必须将作业装入到一段连续的内存空间。

1.拼接技术。

内存中无法使用的内存空间称为碎片或零头。在分区存储管理方式下,系统运行一段时间后,内存中的碎片会占据相当数量的空间。根据碎片出现的位置,可以将碎片分为内部碎片和外部碎片。内部碎片是指分配给作业时未被使用的部分,外部碎片是指系统中无法利用的存储块。如固定分区分配中存在内部碎片,动态分区分配时存在外部碎片。解决碎片问题的方法之一是将存储器中所有已分配区移动到内存的一端,使本来分散的空闲区连成一个大的空闲区。通过移动把多个小空闲分区拼接成一个大的空闲分区的方法称为拼接或紧凑,也可以称为紧缩。在拼接过程中,进程需要在内存中移动,因此要用到动态重定位技术支持。

2.可重定位分区分配技术

在可重定位分区分配算法中,若系统中存在满足作业要求的空闲分区,则按照与动态分区非配相同的方式分配内存;若系统找不到满足作业要求的空闲分区,且系统分区的总容量和大于作业申请的内存空间,则进行拼接。

伙伴系统

固定分区存储管理限制了内存中近程的数目,并且可能存在大量碎片,动态分区虽然能通过拼接技术较好地解决碎片问题,拼接会带来大的系统开销。较为实用的动态存储管理方式——伙伴系统。

伙伴系统结合计算机二进制的特点来划分存储空间,使每个存储块的长度都限制为2的k次方,k为自然数。伙伴系统采用伙伴算法对内存空间进行管理,该方法通过不断对分大的存储块来获得小的存储块。当进程执行完毕释放所占用的空间时,系统应检查释放块的伙伴是否是空闲块,若是则合并为大的空闲块,然后继续找,继续合并,直到找不到空闲的伙伴为止。只有伙伴才能合并,非伙伴不能合并。不足:在分配和回收时,需要对伙伴进行拆分和合并,另外存储空间还有一定的浪费。

覆盖与交换

所谓覆盖技术就是把一个大程序划分为一系列覆盖,每个覆盖是一个相对独立的程序单位,把程序执行时不要求同时装入内存的覆盖组成一组,称为覆盖段,将每一个覆盖段分配到同一个存储区中,这个存储区叫做覆盖区,它与覆盖段一一对应。覆盖段的大小应由覆盖段中最大的覆盖来确定。覆盖技术要求程序员把一个程序划分为不同的程序段,并规定好他们的执行和覆盖顺序,OS按照程序员提供的覆盖结构来完成程序段之间的覆盖。覆盖技术目标是在较小的可用内存中运行较大的内存。

交换技术也称为对换技术,交换是指把暂时不能运行的进程部分(或全部)从内存调换到外存中去,或将重又具备运行条件的进程调入到内存中,并将控制权交给它,让其在系统上运行的一种技术。交换进程由换入和换出两个过程组成。交换技术的特点:增加并发运行的进程数目,并给用户提供适当的响应时间,编写程序时不影响程序结构。

分页存储管理

也称为页式存储管理。

在分页存储管理中,将作业的地址空间划分为若干个大小相等的区域,称为页或页面,每个页面有个编号,称为页号,页号从零开始编号。相应地,也将内存空间划分为与页大小相等的区域,称为块或物理块,同样每个物理块也有编号称为块号,也从零开始编排。在为作业分配内存空间时,总是以块为单位来进行分配,可以将作业的某一页放入内存的某一个空闲块中。作业的大小通常不是页面大小的整数倍,因此最后一页往往装不满,这种浪费的空间称为页内碎片。在调度作业运行时,必须将作业的所有页面一次调入内存,若内存中没有足够的空间,则作业等待。这样的存储管理方式被称为分页存储管理方式,又称简单分页存储管理方式,纯分页存储管理方式。分页存储管理系统中的逻辑地址包括两部分,前一部分是页号P,后一部分是页内位移W,也称做页内地址。一般来说,特定机器的地址结构是确定的。

页表及存储块表

在分页存储管理系统中,进程的各个页面分散存放在内存中,为了便于在内存中找到进程的各个页面所对应的物理块,系统为每个进程建立一张页面映像表,简称页表,记录各页面在内存中对应存放的物理块号。在分页存储管理系统中,也买你的大小选择非常重要。为了实现内存的管理,OS还应该知道内存中的哪些物理块已经使用,哪些物理块空闲,总共有多少物理块等信息。这些信息存放在称为内存块表(MBT)的数据结构中,整个系统只建立一张MBT,记录内存物理块的使用情况。内存块表有两种实现方式。位示图方法:利用一位二进制数表示物理块的状态,1表示物理块已分配,0表示物理块未分配(空闲)。空闲存储块链:将系统中所有的空闲存储块用链表指针链接起来,用空闲物理块中的单元存放指向下一个物理块的指针。

基本地址变换机构

在分页存储管理系统中,逻辑地址到物理地址的变换需要借助页表实现。由于页表通常放在内存中,为了实现的方便,系统中设置了一个页表寄存器,用来存放页表在内存中的地址和页表长度。进程未执行时,页面的起始地址和长度存放在PCB中。当进程执行时,才将页表起始地址(页表地址)和长度存入页表寄存器。当进程要访问某个逻辑地址中的指令或数据时,分页系统的地址变换机构自动将地址分为页号和页内位移,然后以页号为索引去检索页表。在检索之前,先将页号与页表长度比较,若超出页表长度,则表示本次所访问的地址已超越进程地址空间,发出越界中断。若未出现越界,则由页表地址和页号计算出相应页表项的位置,从中得到存放该页的物理块号。最后将物理块号与页内位移拼接在一起,就形成了访问内存的物理地址。

具有快表的地址变换机构

若页表全部存放在内存中,则存取一个数据或一条指令至少需要访问两次内存,一次是访问页表,找到所存取的物理地址,第二次才根据所得到的物理地址存取指令或数据。为了提高地址变换的速度,可以在地址变换机构中增设一个具有并行查找能力的高速缓冲存储器(又称联想存储器或快表),将页表放在这个快表中。高速缓冲存储器一般是由半导体存储器实现的,其工作周期与CPU工作周期大致相同,但造价较高。为了降低成本,通常是在快表中存放正在运行作业当前访问的那些页表项,页表的其余部分依然存放在内存中。在快表中找到指定页表项的次数与总搜索次数的比称作快表命中率。由于成本关系,快表的空间不能再设置太大,一般由几十个单元组成。

多级页表和反置页表。

将页表分为若干较小的片段,离散地存放在内存中;或者只将当前需要的部分表项存放在内存中,其余存放在磁盘上,需要时再动态调入。

多级页表:拥有两级页表的系统中,地址变换的过程是:利用逻辑地址中的一级页号p1作为索引访问一级页表,找到第二级页表的地址;再利用二级页号p2找到指定页表项,从中取出物理块号与页内地址w连接形成物理地址。

反置页表(倒置页表,反向页表):通常每个进程都有一个页表,进程中的每一页在页表中都有一个表项与其对应,也就是说页表是按虚拟地址来排序的,这样OS能够方便地使用页号获得页面存放的物理块号。反置页表为每个物理块设置了一个页表项,并将这些页表项按物理块号大小排序,表项内容为页号以及隶属进程的标识号等信息。这样整个系统只有一个页表,每个内存物理块对应页表中的一个表项。利用反置页表进行地址转换的过程是:利用进程标识号及页号检索反置页表,则该表项的序号就是页面在内存中的物理块号,将物理块号与页内地址拼接就形成了物理地址。如果搜索完整个页表也没有找到相匹配的页表项,则发生了非法地址访问,说明此页目前不在内存,对具有请求调页功能的存储管理系统,应产生请求调页的中断;若系统不支持此功能,则表示地址有错。不足:增加了检索的时间,在支持请求调页的系统中,由于进程的某些页面没有存放在内存中,还必须为进程创建一张传统的页表并存放在外存中,当访问页不在内存时将使用这张页表。

分段存储管理

之前介绍的各种存储管理技术,用户逻辑地址空间是一个线性的地址空间。而通常情况下,一个作业由多个程序段和数据段组成,这就要求编译链接程序将它们按一维线性排列,从而给程序及数据的共享和保护带来了困难。分段存储管理又叫做段式存储管理。

在分段存储管理系统中,作业的地址空间由若干个逻辑分段组成,每个分段是一组逻辑意义相对完整的信息集合,每个分段都有自己的名字,每个分段都从0开始编址并采用一段连续的地址空间。分段存储管理以段为单位分配内存,每段分配一个连续的内存区,但各段之间不要求连续。内存的分配和回收类似动态分区分配。分段存储管理系统的逻辑地址由段号S和段内位移W(段内地址)组成。

断表及地址变换

与分页存储管理类似,为了实现逻辑地址到物理地址的转换,系统为每一个进程建立一个段表,其中每个表项描述一个分段的信息,表项中包括段号、段长及该段的内存起始地址。段表一般放在内存中。

为了便于实现地址转换,系统设置了段表寄存器,用于存放段表起始地址和段表长度。在进行地址转换时,系统将逻辑地址中的段号与段表长度进行比较,若越界则产生越界中断信号,未越界则根据段表起始地址计算出该段对应段表项的位置,从中读出该段在内存中的起始地址,然后检查段内位移是否超出了该段的段长,超出则发出越界中断信号,未越界则将该段的起始地址与段内地址相加得到要访问的物理地址。为了提高访问速度也可以使用快表。

分页与分段的区别

两者都是用离散分配方式,且都要通过地址变换机构来实现地址变换。区别:

(1)页是信息的物理单位,分页是为了实现离散分配方式,以减少内存的碎片,提高内存利用率。段是信息的逻辑单位,它含有一组意义相对完整的信息。

(2)页的大小由系统固定,把逻辑地址分为页号和页内位移,由硬件实现。段的长度不固定,由编译系统在对源程序进行编译时根据信息的性质来划分。

(3)分页系统中作业的地址空间是一维的,而分段系统中作业的地址空间是二维的,程序员在标识一个地址时,既要给出段名又要给出段内位移。

在段页式管理系统中,作业的地址空间首先被分为若干个逻辑分段,每段都有自己的段号,然后再将每一段分为若干个大小固定的页。对于内存空间的管理仍然和分页管理一样,将其分成若干个和页面大小相同的物理块,对内存的分配以物理块为单位。在段页式管理系统中,作业的逻辑地址包括:段号S、段内页号P、及页内位移D。为了实现地址变换,段页式管理系统中需要同时设立段表和页表。系统为每个进程建立一张段表,而每个分段有一张页表。段表表项中至少包括段号、页表始址和页表长度,页表始址指出该段的页表在内存中的起始位地址,页表表项中至少应包括页号和块号。此外,为了便于实现地址变换,系统还要配置一个段表寄存器,其中存放段表的起始地址和段表长度。在进行地址变换时,首先利用段号S与段表寄存器中的段表长度进行比较,若小于段表长度,则说明没有越界,于是,利用段内始址和段号求出该段对应段表项的位置,从中得到该段的页表始址,再利用逻辑地址中的段内号P获得对应页表项的位置,从中读出该页所在的物理块号,然后与页内位移拼接形成物理地址。

最后:

存储分配方式有三种:直接分配方式、静态分配方式和动态分配方式。直接分配是指程序员在编写程序或编译程序对源程序进行编译时采用物理内存地址;静态分配指在作业装入内存时确定他们在内存中的位置,作业一旦进入内存后在整个运行过程中不能在内存中移动,也不能再申请内存空间;动态分配指在装入时确定作业在内存中的位置,但在其运行过程中可根据需要申请附加的内存空间。

猜你喜欢

转载自blog.csdn.net/long_python/article/details/80049070