您的位置:首页 > 其它

操作系统——存储管理(1)

2015-01-23 22:53 609 查看

1、简介

计算机的工作方式归因于它的两个基本能力:一是存储程序,二是执行程序。存储程序依靠存储器来实现,执行程序依靠CPU来实现。计算机的工作原理就是从内存中取出指令然后放到CPU上执行。进程管理是对CPU资源的管理,存储管理就是对存储器资源的管理。通常所说的存储管理,主要是对内存的管理。
早期的存储管理方法主要是:单道程序存储管理,分区存储管理,页式和段式存储管理以及覆盖与交换技术等。当前系统采用的存储管理方式是,虚拟存储技术

2、单道程序存储管理

单道程序存储管理的基本思路是把整个内存划分为两个区域:系统区和用户区。每次把一个应用程序装入到用户区去执行,它和操作系统共享整个内存。每次只能装入一个应用程序。比较适合单用户、单任务的操作系统。
实现单道程序存储管理方案:

操作系统放在随机访问存储器(RAM)的最低端,而剩余部分用来存放正在运行的用户程序。
操作系统放在内存地址的最高端,而且是放在只读存储器(ROM)中,不允许修改。而用户程序则放在低地址部分。主要用在一些掌上电脑和嵌入式系统中。
第三种是早期的个人计算机操作系统采用的方法。操作系统分为两个部分,一部分是一些设备驱动程序放在内存高端的ROM中(这一部分也称为是基本输入输出系统,BIOS),另一部分放在内存地址的最低端,而内存的中间部分用来存放用户程序。

3、分区存储管理(多道程序存储管理)

最简单的多道存储管理方案就是分区存储管理。基本思路就是:把整个内存划分为两大区域:用户区和系统区。然后再把用户区划分为若干个分区,每个进程占用其中的一个分区。这样就可以同时运行多个进程。
分区存储管理有两种实现方式:固定分区和可变分区。

3.1、固定分区存储管理

固定分区存储管理方案的基本思路是:各个用户分区的个数、位置和大小一旦确定后,就固定不变、不能再改变了。
为了满足不同大小的程序的需要,一般会设置多个小分区、适量的中等分区以及少量的大分区。当一个新的进程到来时,需要根据它的大小把它放置到相应的输入队列中,然后等待合适的空闲分区。具体的实现方式上主要有:多个输入队列方式和单个输入队列方式。

多个输入队列方式下,对于每一个用户分区就会有一个相应的输入队列。当一个新的进程到来时,就根据它的大小把它放在相应的一个输入队列中。

单个输入队列方式下,对于所有的用户分区只设置一个统一的输入队列。当一个新的进程到来时,就把它加入到这个输入队列中。当某个分区空闲的时候,再从这个队列中选择一个合适的进程,把它装入到合适的分区中。

在选择合适的进程的时候有两种方法:第一种是最先匹配法,即选择离队首最近的,能够装入该分区的进程。第二种方法是最佳匹配法,即先搜索整个队列,从中选择能够装入该分区的最大进程,从而尽可能地少浪费空间。

在实现固定分区存储管理方案时,首先要设计一个数据结构,即内存分配表,来记录内存的使用情况。
内存分配表

分区号起始地址长度状态进程名
1100KB100KB已占用P1
2200KB200KB已占用P3
3400KB300KB空闲
4700KB100KB已占用P2

缺点:

内存的利用率不高,内碎片造成很大的浪费。内碎片就是在进程所占用的分区内部,未被利用的空间。也就是说分区比进程占用的空间大。
分区的总数固定,限制了并发执行的程序的个数。
缺乏内存保护,一个应用程序可能会破坏操作系统或其他的应用程序。
每个应用程序的地址空间的大小有限,不能超过物理内存的大小。

3.2可变分区存储管理

可变分区存储管理的基本思路是:分区不是预先划分好的固定分区,而是动态创建的。在装入一个程序时,系统将根据它的需求和内存空间的使用情况来决定是否分配。也就是说在系统生成后,操作系统会占用一部分内存,一般位于内存地址的最底端。其余部分的空间则是一个大的完整的空闲区。当一个应用程序要求装入内存运行时,系统就会从这个分区中划分出一块分配给它,当程序运行完毕之后,再释放该部分内存。

缺点:

在内存中可能会存在外碎片。外碎片就是在各个被占用的分区之间,难以利用的一些空闲分区,一般都是一些比较小的分区。
与固定分区相比,这种可变分区的做法,使得内存的分配、回收和管理变得更加复杂了。

3.3可变分区的实现

如何实现可变分区存储管理技术?需要解决一下四个问题:内存管理的数据结构,内存的分配算法,内存的回收方法,外碎片问题。

分区链表(数据结构)

内存管理的数据结构就是分区链表。分区链表是由操作系统来维护的,用来跟踪记录每一个内存分区的当前情况,包括该分区的状态(已分配或空闲)、分区的起始地址、长度等信息。

基本思路是:对于内存中的每个分区,分别创建一个链表结点,里面记录了该分区的各种信息,包括当前状态(已占用或空闲),分区的起始地址和长度。然后把所有的结点用指针按起始地址递增顺序链接起来,这样就得到一个分区链表。也就是说每一个链表结点与一个内存分区都是一一对应的。

分区分配算法

分区分配算法是指当一个新的进程来到时,需要为它寻找某个空闲分区,该空闲分区的大小必须大于或等于这个进程的要求。如果大于要求,就把该空闲分区分割成两个小分区,一个为要求的大小,并标记为占用,另外一个分区为剩下的部分并标记为空闲。分区的先后顺序是从内存低端到高端。

通常的分区分配算法包括:最先匹配法,下次匹配法,最佳匹配法和最坏匹配法。

①最先匹配法:假设新的进程对内存大小的要求是M,从分区链表的首结点开始,将每一个空闲结点的长度与M进行比较,看是否大于或等于它,直到找到第一个符合要求的结点。然后把对应的空闲分区,分为两个分区,一个用来装入进程,另一个是剩余的空闲分区。相应的结点也要一分为二,并修改相应的内容,包括分区的状态,起始地址和长度等。
②下次匹配法:与最先匹配法类似,只不过每一次当它找到一个合适的空闲结点时,就把当前的位置记录下来。然后等下一次又有一个新的进程到来的时候,就从这个位置开始继续往下找。不像最先匹配法那样每次都从链表的首结点开始找。
③最佳匹配法:将申请内存的进程装入到与其大小最接近的那个空闲分区中。
④最坏匹配法:每次分配时,总是将最大的那个空闲分区切去一部分,分配给请求者。

分区回收算法

当一个进程运行结束时,需要回收它占用的内存分区。在固定分区存储管理方案中,分区的回收很简单,只要将该分区标记为空闲就行。在可变分区存储管理方案中,当一个进程释放了它占用的分区后,需要将相邻的几个空闲分区合并为一个大的空闲分区。

碎片问题

在可变分区存储管理方法中,随着系统的运行,在经过一段时间的分配和回收之后,在内存中会存在很多不连续的很小的空闲分区。这个时候,如果有一个新的进程到来,这些小的分区都不能满足这个进程的要求,但是他们的总和可以满足这个进程的要求,这种情况就是所谓的外碎片问题。

解决办法:采用内存紧缩技术,把所有的进程都尽可能往内存地址的低端移动,相应的,那些空闲的小分区就会往地址的高端移动。从而,地址高端就会形成一个比较大的空闲分区。但是需要解决两个技术难题:一是它需要把所有的进程都移动一定的距离,这就需要大量的CPU时间。二是当各个进程被移动之后,还需要解决其程序里面的地址重定向问题,因为它们在内存中的地址都已经发生了变化。

3.4内存中的程序运行

当一个程序被装入到某个分区之后,变成进程之后,这个分区的内部结构是什么样子?

一个源文件在经过编译链接之后,该源文件就变成了一个可执行文件。一个可执行文件由四个部分组成:文件头(存放这个可执行文件的一些描述信息,比如每个部分的起始地址和长度),代码区(存放的是可执行指令),数据区(存放的是程序的全局变量)。只有全局变量才存放在可执行文件中,而局部变量则不需要,以为局部变量是在函数调用的时候在栈空间中分配相应的存储空间。

可执行文件的结构

文件头
代码区
数据区
内存分区

动态堆空间
数据段
代码段
当可执行文件装入到某个分区之后,就变成了上图中所示的样子。可执行文件中的代码区的内容被复制到该内存分区的起始地址形成代码段;数据区的内容被复制到代码段的上面形成数据段;栈指针指向这个内存分区的最高点。在栈和数据段之间是堆空间。然后程序计数器PC指向代码段的起始地址,这就可以一条一条的执行指令了。
在指令的执行过程中,如果需要去访问全局变量,就去访问数据段。如果要去访问动态分配的内存空间,就去访问堆空间。如果发生了函数调用,就在栈中分配一块栈帧,用来存放形参和局部变量。

3.5重定位和存储保护

1、地址映射(地址重定位)

物理地址也叫内存地址、绝对地址或者实地址。在访问内存的时候,只有通过物理地址,才能对内存单元进行直接访问,物理地址是对内存每一个存储单元分配的编号。
逻辑地址也叫相对地址或者虚地址。用户的源程序在经过汇编或编译后会形成目标代码,而目标代码通常采用的就是相对地址的形式。首地址是0,其余指令中的地址是相对于这个首地址进行编址的。
逻辑地址和物理地址不同,不能使用逻辑地址来访问内存。为了保证CPU在执行指令时,能够正确的访问内存单元,需要将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这个过程就称为是地址映射。

第一种地址映射方式是静态地址映射,或者叫静态重定位。基本思路是:当用户程序被装入到内存时,直接对指令代码进行修改,一次性实现逻辑地址到物理地址的转换,以后不再转换。在实现时,在每一个可执行文件中,需要列出各个需要重定位的地址单元的位置,然后在装入时,由一个专门的装入程序(加载程序)来完成这个装入过程。也就是说指令中的每一个逻辑地址都被修改为相应的物理地址。
第二种地址映射方式是动态地址映射,或者叫动态重定位。基本思路是:当用户程序被装入到内存时,不对指令代码进行任何修改,而是在程序的运行过程中,当它需要访问内存单元时,再进程地址转换。在实现时,由硬件的地址映射机制来完成,做法是设置一个基地址寄存器(重定位寄存器)。当一个进程被调度运行时,就把它所在分区的起始地址装入到这个寄存器中。然后在程序运行过程中,需要访问内存单元时,硬件就自动将其中的相对地址加上基地址寄存器当中的内容,从而得到实际的物理地址,然后按照这个新的地址去执行。

2、存储保护

在多道程序并发运行时,操作系统位于内存中,多个进程也位于内存中。为了防止一个进程去访问其它进程的内存区域,必须进程存储保护。
实现的方法:在基地址寄存器的基础上,再增加一个限长寄存器,用来记录相应的内存分区的长度。这两个寄存器在一起就定义了进程所在的分区。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: