四:存储管理
存储器管理负责管理计算机系统中重要的资源---主存储器。任何程序和数据必须载入到主存中才得以执行和处理,因此存储器管理的优劣直接影响系统的性能。
主存分为两部分:一部分是系统区,用于存放操作系统内核程序和数据结构等。另一部分是用户区,用于存放应用程序和数据。
计算机系统采用层次结构的存储系统。以便在容量大小、速度快慢、价格高低等诸多因素中取得平衡。它分为五个层次:寄存器,高速缓存,主存储器,磁盘,磁带等五层。寄存器,高速缓存和主存储器属于操作系统存储管理管辖范畴。磁盘和磁带属于设备管理的管辖对象。
由于程序在执行和处理数据时往往存在顺序性和局部性,因此在执行时并不需要将其全部调入主存,而仅调用当前使用的一部分,其他部分待需要时再逐步调入。基于这个原理操作系统可以向用户提供比实际主存大得多的存储空间,可以设计出多级层次式体系结构的存储子系统。
源程序经过编译,链接,装入三个阶段后才能装入主存执行。一个程序可由独立编写且具有不同功能的多个源程序模块组成。由于模块包含外部引用:指向其他模块中的数据或函数的地址或包含对库函数的引用。编译程序负责记录引用的发生位置,编译或汇编的结果将产生相应的多个目标模块,每个模块都附有供引用使用的内部符号表和外部符号表。符号表中依次给出个符号名及在本目标模块中的名字地址,在模块被链接时进行转换。
链接程序的作用是把多个目标模块链接成一个完整的可重定位程序,这需要解析内部和外部符号表,把对符号的引用转换为数值引用,将对符号引用的程序入口点和数据引用点转换为数值地址。Linker首先将主程序调入工作区,然后扫描外部符号表,获得外部符号。用取得的符号名从标准函数库或其他库中找出此符号对应的.o文件,装入工作区并拼接到主程序之后作为程序的一部分。
磁盘中存储的代码模块使用的是逻辑地址。逻辑地址空间可以是一维的,从0开始线形排列。也可以是二维的,此时整个程序被分为多个段,每段都有不同的段号,段内地址从0开始编址。
进程运行时,数据和代码模块被装入物理地址空间,程序和数据的实际地址通常不可能同原来的逻辑地址一致。把逻辑地址转换为物理地址的过程称为地址重定位(与基址重定位相区别)。有两种方式:
1:静态地址重定位:由载入程序实现地址转换,将所有的逻辑地址修改成主存物理地址。地址转换工作在进程执行前一次完成,无须硬件支持,易于实现,但是不允许程序在进程中移动位置。早期的计算机系统使用此方法。
2:动态地址重定位:加载程序将程序的数据和代码加载到指定的主存区域后,并不对链接器处理过的应用程序的逻辑地址进行修改,但程序在主存的起始地址被置入硬件专用寄存器---重定位寄存器。程序执行过程中,每当cpu访问数据和代码时,由硬件截取此逻辑地址,并在它被发送到主存储器之前加上重定位寄存器的值以便实现地址转换。这被称为动态重定位,地址转换被推迟到最后的可能时刻--执行时才完成。这允许程序在主存中移动,便于程序共享且主存利用率高。
为了支持动态重定位cpu至少要有三个重定位寄存器。将代码段、数据段和堆栈段分别作为三个可重定位的模块。Intel x86有6个重定位寄存器。
要将动态地址重定位与根据重定位段进行的基址重定位区分开来。基址重定位是当exe或dll没有加载到其首选基址时,所有涉及对逻辑地址引用的代码都需要修改成相对于exe或dll实际载入的逻辑地址条件下的偏移地址。它是对逻辑地址进行操作。而当exe或dll被加载到首选基地址时,基址重定位不会发生。但是任何程序都会进行动态地址重定位,将逻辑地址转换为物理地址。
在多道程序设计中,可用的主存通常被多个进程共享,必须允许进程所使用的内存因对换或空闲区收集而被移动,这需要动态地址重定位支持。无论采取何种重定位方式,通常进程运行时会对需要访问所有主存地址进行检查,确保进程仅访问自己的存储区。这就是地址越界保护,它依赖于硬件。除了地址越界保护之外,还要进行访问权限检查,如允许读、写、执行等,从而保证数据的安全性和完整性,这就是信息存取保护。
固定分区存储管理的基本思想:主存空间被划分成数目固定不变的分区,各个分区大小不等,每个分区只装入一个作业,若多个分区都装有作业则它们可以并发执行。缺点:预先规定分区大小使得大作业无法装入。作业很少会恰好填满分区,主存利用率不高。
可变分区管理又称为动态分区管理,按照作业大小来划分分区,但划分的时间、大小、位置都是动态的。系统把作业装入主存时,根据其所需要的主存容量查看是否有足够的空间。若有,则按需分配一个分区给此作业;若无,则令此作业等待主存资源 。由于分区大小是按需求而定的,因此分区数目是可变的。这可以提高主存利用率。
用于管理的数据结构由两张表组成:已分配分区表和未分配区表。当装入新作业时,从未分配表中找出一个足够容纳它的空闲区。将此区分成两部分,一部分用来装入作业,另一部分仍是空闲区。然后在已分配的表中登记新作业的起始地址、占用长度,同时修改未分配区表中空闲区的长度和起始地址。当作业撤离时,已分配区表中的相应状态变为空,而将收回的分区登记到未分配区表中,若有相邻空闲区,将其合并后登记。
已分配分区表和未分配分区表采用链表是不错的选择。在内部各分区都可按一定的规则排列。如按空闲区大小、地址排列。
常用的可变分区分配算法有以下五种:
1:最先适应分配算法:顺序查找未分配表找出一个满足需要的。
2:下次适应分配算法:总是从未分配区的上次扫描结束处顺序查找未分配区表。
3:最优适应分配算法:扫描整个未分配区表,从中找出一个能满足需要的最小分区进行分配。查找前分区一般按大小排列。
4:最坏适应分配算法:扫描整个未分配分区表,总是挑选一个最大的空闲区分割给作业使用。
5:快速适应分配算法:为那些经常使用的长度设立单独的空闲区链表。
对可变分区需采用动态地址重定位,进程的程序和数据的地址转换由硬件完成,硬件设置两个专用控制寄存器:基址寄存器和限长寄存器。基址寄存器存放分配给进程使用的分区的起始地址,限长寄存器存放进程所占用的连续存储空间的长度。当进程占有cpu运行后,操作系统可把分区的起始地址和长度送入基址寄存器和限长寄存器,在执行指令或访问数据时,由硬件根据基址寄存器进行地址转换得到绝对地址。
当逻辑地址小于限长值时,逻辑地址加上基址寄存器的值就可以获得绝对地址。当逻辑地址大于限长值时表示进程所访问的地址超过所分得的区域,此时不允许访问。
C语言的程序会被编译成至少三个段:代码段,数据段,堆栈段。Intel x86平台提供专用的存放段基址的寄存器:代码段寄存器CS在指令执行期间重定位指令地址;堆栈段寄存器SS为栈指令执行重定位地址;数据段寄存器DS在指令执行周期内重定位其他地址。提供多对基址、限长寄存器的机器中,允许一个进程占用两个或多个分区。可规定某对基址、限长寄存器的区域是共享的,用来存放共享的程序和数据。
可变分区中常常出现分散的小空闲区,称之为碎片。当在分区表中找不到足够大的空闲区来装入进程时,可采用移动技术把已在主存中的进程分区连接到一起,使分散的空闲区汇集成片。这就是移动技术。第一种方法是把所有当前占用的分区移动到主存一端。第二种是也是把占用分区移动到另一端,但是当产生足够大的空闲区就停止移动。
分区方式管理存储器,每道程序要求占用主存的一个或多个连续存储区域,这样不仅导致主存中产生碎片,而且处理器的开销太大。分页存储管理允许程序存放到若干不相邻的空闲块中,既可以免除移动信息工作也可充分利用主存空间。
进程逻辑地址空间分成大小相等的区,每个分区成为页面或页,页号从0开始依次编号。 把主存物理地址空间分成大小相等的区,每个区是一个物理块或页框。页框大小与页面大小相等。
与此对应分页存储器的逻辑地址由两部分组成:页号和页内位移。逻辑地址是连续的,用户在编制程序时仍使用相对地址,不必考虑如何分页,由硬件地址转换机构和操作系统的管理需要来决定页面尺寸,从而确定主存的分块大小。进程在主存中的每个页框内的地址是连续的,但页框之间的地址可以不连续。
页表用于是操作系统为进程建立的,是程序页面和主存对应页框的对照表。页表中的每一栏指明程序中的一个页面和分得页框之间的对应关系。从数学角度来看,页表表示一个函数,其变量是页面号,函数值为页框号,通过页表可以把逻辑地址中的逻辑页面替换成物理页框。进程页表存放在内存中,系统设置了专门的硬件:页表基址寄存器(一对,地址和长度),存放当前运行进程页表的起始地址 ,以加快地址转换速度。
进程运行前由系统把它的页表基地址送入页表基址寄存器,运行时借助于硬件的地址转换,按页面动态地址重定位。当cpu获得逻辑地址后,由硬件按设定的页面尺寸分成两部分:页号和页内位移。先从页表基地址寄存器找到页表基地址,再用页号作为索引查找页表,得到对应的页框号。根据
物理地址=页框号*块长+页内位移。
计算出欲访问的主存单元。虽然进程存放在若干不连续的页框中,
但在执行过程中总能按正确的物理地址进行存取。
按照给定逻辑地址进行读写操作时,至少访问两次主存:一次访问页面,另一个根据物理地址访问指令或数据。为了提高运算速度,设置了专门的硬件,用来存放进程最近访问的部分页表项,被称为转换后援缓冲或快表。对快表的访问速度远快于主存,但造价高,且只能存储几十个页表项。块表项包含页号及对应的页框号,它通过并行匹配对所有快表项进行查找。如果找不到,再查主存中的页表,同时将页号即页框号登记到快表中。当块表快满时,需要淘汰旧的块表项,最简单的策略是先进先出。
通过快表实现主存访问的比率成为命中率。快表与高速缓存不同,前者记录最近转换的页号即页框号,后者保存最近实际访问的指令或数据的副本。
分页存储管理能实现多个进程共享程序和数据,共享页面信息可大大提高主存空间的利用率。实现页面共享必须区分数据共享和程序共享。实现数据共享时,允许不同进程对共享的数据页面用不同的页号,只要让各自页表中的有关表项指向共享的数据页框。实现程序共享时,由于指令包含指向其他指令或数据的地址,进程依赖于这些地址才能执行,所以,不同进程正确执行共享代码页面,必须为它们在所有逻辑地址空间中指定同样的页号。实现信息共享必须解决共享信息的保护问题,通常的做法是在页表中增加标志位,指出此页的访问模式。进程访问时核对访问模式,当模式不符时抛出异常。
分页存储管理是实存管理,必须为进程分配足够的主存空间,装入其全部信息,否则进程无法运行。把进程的全部信息装入主存后,实际上并非同时使用,有些部分甚至从不使用,这是对主存资源的一种浪费。于是提出一种想法:不必装入进程的全部信息,仅将当前使用部分先装入主存,其余部分存放在磁盘中,待使用时由系统自动将其装进来,这就是虚拟存储管理技术的基本思路。
当进程被创建时,代码段和数据段部分数据被调入内存。如果处理器访问的程序或数据不在内存,系统自动将这部分信息从磁盘装入,这叫做部分装入。若此时内存没有足够的空闲空间,便把主存中暂时不用的信息移至磁盘,这叫做部分替换。在具有层次存储结构的计算机系统中,自动实现部分装入和部分替换功能,能从逻辑上为用户提供一个比实际物理存储器大得多的、可寻址的“主存储器”,这被称为虚拟存储器。它对用户隐蔽内部细节。虚拟地址空间等同于实际物理主存加部分硬盘区域的存储空间。引用基础是:程序执行的局部性原理:某存储单元被使用后,其相邻的存储单元也很快被使用---空间局部性。最近访问过的程序代码和数据很快被访问---时间局部性。
虚拟存储器是基于程序局部性原理的一种假想的而非物理存在的存储器,其主要任务是:基于程序局部性特点,当进程使用某部分地址空间时,保证将相应部分加载至主存中。这种将物理空间和逻辑空间分开编制、互相隔离,但又统一管理和使用的计数为用户编程提供了极大地方便。
虚拟存储管理与对换有很大区别。兑换技术以进程为单位,当所需的主存空间大于当前系统的拥有量时,进程无法对换进主存工作。而虚拟存储管理以页或段为单位,即使进程所需主存空间大于当前系统拥有的主存总量,仍然能够正常运行。
操作系统的存储管理依靠底层硬件MMU(主存管理部件)来完成,它提供地址转换和存储保护的功能。
每当进程上下文发生切换时,系统负责把要运行的进程的页表基地址装入页表寄存器,此页表便成为活动页表。MMU只对页表基址寄存器所指出的活动页表进行操作。然后将逻辑地址分解为页面号和页内位移,以便进行地址转换。对快表的管理设计两个方面:一是直接查找快表,找到相应的页框后去拼接物理地址。二是装入表目和清除表目,每次发生快表查找不命中的情况后,待缺页中断处理结束,把相应的页面和页框号装入。
请求分页虚拟存储管理是将进程信息的副本存放在辅助存储器中,当它被调度投入运行时,并不把程序和数据全部装入主存,仅装入当前使用的页面,访问到不在主存的页面时再动态的把所需的信息装入。请求分页:当需要执行某条指令或使用某个数据而发现它们不在主存时,产生缺页中断,系统从磁盘把此指令或数据所在的页面装入。
请求分页虚拟存储管理属于虚拟存储,与分页实存管理不同,仅让当前使用部分装入,必然会发生某些页面不在主存的情况,为了标记页面是否在主存中,所采用的方法为:扩充页表项的内容,增加驻留标志位,又称页失效异常位,用来指处页面是否装入主存。当访问一个页面时,如果某页的驻留标识为1,表示此页已经在主存中,可被正常访问。如果某页的驻留标识为0,不能立即访问,产生缺页中断,操作系统根据磁盘地址将这个页面调入主存,然后重新启动相应指令。
页面装入策略决定何时把页面装入主存,有两种策略:
1:请页式,仅当需要访问程序和数据时,通过缺页中断并由缺页中断处理程序分配页框,把所需页面装入主存。
2:预调式,装入主存的页面并非缺页中断请求的页面,是由操作系统依据某种算法,动态预测进程最可能要访问的那些页面。
页面清除策略与装入策略相对应,要考虑何时把修改过的页面写回辅助存储器,常用的算法是:
1:请页式清除,仅当一页被选中进行替换且被修改过,才把它写回磁盘。
2:预约式清除,对于所有更改过的页面,在需要替换之前把它们都写回磁盘。
在多道程序设计中,属于不同进程的页面被分散存放在主存页框中,当发生缺页中断时,如果已无空闲页框,系统要选择一个驻留页面进行淘汰。
页面替换有两种策略:
1:局部替换,页面替换算法局限于进程自身。
2:全局替换,页面替换算法的作用范围是整个系统。
全局替换算法有以下几种算法:
1:最佳页面替换算法(optimal replacement ,OPT):当要调入一页而必须淘汰旧页时,应该淘汰以后不再访问的页,或距现在最长时间后要访问的页。它所产生的缺页数最少。这只是一种理想的情况。
2:先进先出页面替换算法(FIFO)
基于程序总是按线形顺序来访问物理空间这一假设,总是淘汰最先调入主存的页面,即淘汰在主存中驻留时间最长的页面。
3:最近最少使用页面替换算法(Least Recently Used ,LRU)
淘汰的页面是在最近一段时间内最久未被访问的那一页。
4:第二次机会页面替换(Second Chance Replacement ,SCR)
此算法是将FIFO算法与页表中的引用位结合起来使用,实现思想:首先检查FIFO页面队列中的队首,这是最早进入主存的页面,如果其引用位是0,那么这个页面不仅入队时间长,而且没有使用。如果引用位为1,说明它进入主存的时间较早,但最近仍在使用,于是将其引用位归0,置于队尾,把它看成新调入的页,再给一次机会。
5:时钟页面替换算法(Clock policy replacement)