内存的分配与管理
为什么要引入内存管理?
答:多道程序并发执行,共享的不仅仅只有处理器,还有内存,并发执行不过不进行内存管理,必将会导致内存中数据的混乱,以至于限制了进程的并发执行。
内存连续分配方式
连续分配方式,是指为一个用户程序分配一个连续的内存空间。它主要包括单一连续分配、固定分区分配和动态分区分配。
1.单一连续分配
内存划分为系统区和用户区 ,整个用户区为一道用户程序独占,仅驻留一道程序, 基本不设立存储器保护措施,最多需要设立界限检 查机制保护用户程序不要破坏操作系统 ,仅适用于单用户、单任务操作系统中。
2.固定分区分配
固定分区分配是最简单的一种多道程序存储管理方式,它将用户内存空间划分为若干个固定大小的区域,(但分区的大小不一定相等),每个分区只装入一道作业。当有空闲分区时,便可以再从外存的后备作业队列中,选择适当大小的作业装入该分区,如此循环。
为便于内存分配,通常将分区按大小排队,并为之建立一张分区说明表,其中各表项包括每个分区的起始地址、大小及状态(已分配或空闲)。当有用户程序要装入时,便检索该表,以找到合适的分区给予分配并将其状态置为”已分配”;未找到合适分区则拒绝为该用户程序分配内存 。
缺点:
(1)程序可能太大而放不进任何一个分区中,这时用户不得不使用覆盖技术来使用内存空间 ;
(2)主存利用率低,当程序小于固定分区大小时,也占用了一个完整的内存分区空间,这样分区内部有空间浪费,这种现象称为内部碎片。
3.动态分区分配
动态分区分配又称为可变分区分配,是一种动态划分内存的分区方法。这种分区方法不预先将内存划分,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统中分区的大小和数目是可变的。
如上图,动态分区在开始分配时是很好的,但是之后会导致内存中出现许多小的内存块。随着时间的推移,内存中会产生越来越多的碎片,内存的利用率随之下降。这些小的内存块称为外部碎片,指在所有分区外的存储空间会变成越来越多的碎片,这与固定分区中的内部碎片正好相对。
克服外部碎片可以通过紧凑技术来解决,就是操作系统不时地对进程进行移动和整理。但是这需要动态重定位寄存器的支持,且相对费时。紧凑的过程实际上类似于Windows系统中的磁盘整理程序,只不过后者是对外存空间的紧凑。
动态分区分配算法 :
- 首次适应算法:空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。
- 优点:最简单,最快,有利于大作业分配。
- 缺点:会使得内存的低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。
- 最佳适应算法:空闲分区按容量递增形成分区链,找到第一个能满足要求的空闲分区。
- 缺点:性能通常很差,因为每次最佳的分配会留下很小的难以利用的内存块,它会产生最多的外部碎片。
- 循环首次适应算法:由首次适应算法演变而成。不同之处是分配内存时从上次查找结束的位置开始继续查找。
- 缺点:邻近适应算法试图解决查找开销这个问题,但实际上,它常常会导致在内存的末尾分配空间(因为在一遍扫描中,内存前面部分使用后再释放时,不会参与分配),分裂成小碎片。它通常比首次适应算法的结果要差。
- 最坏适应算法:空闲分区以容量递减的次序链接。找到第一个能满足要求的空闲分区,也就是挑选出最大的分区。
- 选择最大的可用块,这看起来最不容易产生碎片,但是却把最大的连续内存划分开,会很快导致没有可用的大的内存块,因此性能也非常差。
动态可重定位分区分配方式
在连续分配方式中,必须把一个系统或用户程序装入一连续的内存空间。如果在系统中只有若干个小的分区,即使它们容量的总和大于要装入的程序,但由于这些分区不相邻接,也无法把该程序装入内存。
若想把作业装入,可采用的一种方法是:将内存中的所有作业进行移动,使它们全都相邻接,这样,即可把原来分散的多个小分区拼接成一个大分区,这时就可把作业装入该区。这种通过移动内存中作业的位置,以把原来多个分散的小分区拼接成一个大分区的方法,称为“拼接”或“紧凑 。
由于经过紧凑后的某些用户程序在内存中的位置发生了变化,此时若不对程序和数据的地址加以修改(变换),则程序必将无法执行。为此,在每次“紧凑”后,都必须对移动了的程序或数据进行重定位。
动态重定位的实现
在动态运行时装入的方式中,作业装入内存后的所有地址都仍然是相对地址,将相对地址转换为物理地址的工作,被推迟到程序指令要真正执行时进行。为使地址的转换不会影响到指令的执行速度,必须有硬件地址变换机构的支持,即须在系统中增设一个重定位寄存器,用它来存放程序(数据)在内存中的起始地址。程序在执行时,此时已完成紧凑操作,真正访问的内存地址是相对地址与重定位寄存器中的地址相加而形成的。
覆盖和交换技术是在多道程序环境下用来扩充内存的两种方法。
覆盖技术主要用在早期的操作系统中,而交换技术则在现代操作系统中仍具有较强的生命力。
覆盖技术
把程序划分为若干个功能上相对独立的程序段,按照其自身的逻辑结构使那些不会同时运行的程序段共享同一块内存区域。程序段先保存在磁盘(外存)上,当有关程序的前一部分执行结束后,把后续程序段调入内存,覆盖前面的程序段。
一个覆盖区的大小:为了使一个覆盖区能为相应覆盖段中的每个覆盖在不同时刻共享,其大小应由覆盖段中的最大覆盖来确定。
例如,一个用户程序由6个模块组成,下图给出了各个模块的调用关系,Main模块是一个独立的段,其调用A和B模块,A和B是互斥被调用的两个模块。在A模块执行过程中,调用C模块;而在B模块执行过程中,它可能调用D或E模块(D和E模块也是互斥被调用的)。为该用户程序建立的覆盖结构如下:Main模块是常驻段,其余部分组成两个覆盖段 。
由以上推理可知,A和B模块组成覆盖段1,C、D和E组成覆盖段2。为了实现真正覆盖,相应的覆盖区应为每个覆盖段中最大覆盖的大小。
覆盖技术的特点是打破了必须将一个进程的全部信息装入主存后才能运行的限制,但当同时运行程序的代码量大于主存时仍不能运行。
对换技术
在多道程序环境下,一方面,在内存中的某些进程由于某事件尚未发生而被阻塞运行,但它却占用了大量的内存空间,甚至有时可能出现在内存中所有进程都被阻塞而迫使 CPU停止下来等待的情况;另一方面,却又有着许多作业在外存上等待,因无内存而不能进入内存运行的情况。显然这对系统资源是一种严重的浪费,且使系统吞吐量下降。
为了解决这一问题,在系统中又增设了对换(也称交换)设施。所谓“对换”,是指把内存中暂时不能运行的进程或者暂时不用的程序和数据调出到外存上,以便腾出足够的内存空间,再把已具备运行条件的进程或进程所需要的程序和数据调入内存。对换是提高内存利用率的有效措施。
对换其实就是中级调度 。可以参考处理机的多级调度。
- 如果对换是以整个进程为单位的,便称之为“整体对换”或“进程对换”。这种对换被广泛地应用于分时系统中,其目的是用来解决内存紧张问题,并可进一步提高内存的利用率。
- 如果对换是以“页”或“段”为单位进行的,则分别称之为“页面对换”或“分段对换”,又统称为“部分对换”。这种对换方法是实现后面要讲到的请求分页和请求分段式存储管理的基础,其目的是为了支持虚拟存储系统。
对换空间的管理
在具有对换功能的 OS 中,通常把外存分为文件区和对换区。前者用于存放文件,后者用于存放从内存换出的进程。
由于通常的文件都是较长久地驻留在外存上,故对文件区管理的主要目标,是提高文件存储空间的利用率,为此,对文件区采取离散分配方式。
然而,进程在对换区中驻留的时间是短暂的,对换操作又较频繁,故对对换空间管理的主要目标,是提高进程换入和换出的速度。为此,采取的是连续分配方式,较少考虑外存中的碎片问题。
为了能对对换区中的空闲盘块进行管理,在系统中应配置相应的数据结构,以记录外存的使用情况。其形式与内存在动态分区分配方式中所用数据结构相似,即同样可以用空闲分区表或空闲分区链。在空闲分区表中的每个表目中应包含两项,即对换区的首址及其大小,分别用盘块号和盘块数表示。
由于对换分区的分配是采用连续分配方式,因而对换空间的分配与回收,与动态分区方式时的内存分配与回收方法雷同。其分配算法可以是首次适应算法、循环首次适应算法或最佳适应算法。
进程的换入和换出
(1) 进程的换出。每当一进程由于创建子进程而需要更多的内存空间,但又无足够的内存空间等情况发生时,系统应将某进程换出。其过程是:系统首先选择处于阻塞状态且优先级最低的进程作为换出进程,然后启动磁盘,将该进程的程序和数据传送到磁盘的对换区上。若传送过程未出现错误,便可回收该进程所占用的内存空间,并对该进程的进程控制块做相应的修改。
(2) 进程的换入。系统应定时地查看所有进程的状态,从中找出“就绪”状态但已换出的进程,将其中换出时间最久(换出到磁盘上)的进程作为换入进程,将之换入,直至已无可换入的进程或无可换出的进程为止。
交换的特点是打破了一个程序一旦进入主存便一直运行到结束的限制,但运行的进程大小仍受实际主存的限制。
与覆盖技术相比,交换不要求程序员给出程序段之间的覆盖结构,而且交换主要是在进程或作业之间进行;而覆盖则主要在同一个作业或进程中进行。另外,覆盖只能覆盖与覆盖程序段无关的程序段。