在之前的章节中,我们到了内存管理,其中有一个很重要的功能,就是对操作系统中的内存进行分配和回收。
那如何对操作系统的内存进行分配呢? 整体上可以分为两种方式:连续分配管理方式、非连续分配管理方式。
这里提到的连续分配
是指:为用户进程分配的内存空间,必须是一个连续的内存空间地址。
在连续分配管理方式,有划分了三种不同的方式,接下来我们一起来详细看看:
单一连续分配
在单一连续分配方式中,内存被划分为:系统区和用户区,系统区通常位于内存的低位置,用于存放操作系统相关数据,用户区就存放用户进程相关数据。
在单一连续分配模式中,内存空间只能有一道用户程序,用户程序独占整个用户区空间。 这样分配实现简单,可以采用覆盖技术扩充内存,但是缺点也很明显,只能用于单用户、单任务的操作系统中,有内部碎片,内存利用率低。
这里提到了一个概念:内存碎片
,这里来解释一下,看下图:
当给用户区放入了用户进程A之后,还空闲了很大一块区域,这么区域就叫做内部碎片
,也就说明这种方式内存利用率低。
固定分区分配
在后期计算机在不断的发展,为了能在内存中装入多个程序,并且这些程序之间又不会相互干扰,于是将整个用户空间划分为若干个固定大小的分区,在每一个分区中只转入一个进程,这样就形成了最早的,最简单的一种可运行多道程序的内存管理方式。
固定分配也分为了两种方式:分区大小相等、分区大小不相等,如图:
那这两种方式有什么优缺点呢?
分区大小相等:缺乏灵活性,比如说一个进程只需要 2 MB、5 MB,但他们都需要各占 10 MB ,内部碎片太严重了,利用率很低。 但是这种方式比较合适用于一台计算机,同时执行相同进程的进程,每个进程所占用的内存大小都是相等的。
分区大小不等:增加了灵活性,可以满足不同大小的进程需求,可以根据系统中运行的进程大小,进行划分。
既然固定分配支持多个进程在内存中同时运行,那操作系统是如何管理哪些分区是空闲的,哪些分区是非空闲的呢?
在这个时候,操作系统需要建立一个分区说明表
,来实现各个分区的分配和回收:如下图:
在这个表中就能记录各个分区的使用情况,以及大小和起始地址。如果现在有一个进程需要转入到内存中,操作系统就可以根据这个分区说明表
来检索,从里面找到一个能满足大小的、未分配的区分,分配给这个进程,然后修改状态为:已分配
.
但是大家思考一下,这种固定划分的方式,如果有一个进程所需要的内存大小很大,可能所有的分区都不能满足的时候,这个时候又需要采用覆盖或者交换的技术来扩充,这样又会增加复杂度,并且降低新性能。 固定分配也有可能产生内部碎片,内存利用率低。
动态分区分配
动态分区分配又称之为可变分区分配,这种分配方式不需要预先划分内存,而是在进程装入内存时,根据进程的大小动态建立分区,并使分区的大小正好适合进程的需要,因此系统分区大小和数量是可变的。
在这里,我们也来思考三个问题:
1、系统要用什么样的数据结构来记录内存的使用情况?
两种常用的数据结构:
空闲分区表
:每个空闲分区对应一个表项,表项里面包含了分区号、分区大小、起始地址、状态
空闲分区链
:每个分区的起始部分和末尾部分分别设置向前指针和向后指针。
2、当很多空闲分区都能满足需求的时候,应该选择哪个分区进行分配?
把一个新的进程装入到内存时,必须按照一定的动态分区分配算法
,从空闲的分区表中挑选一个分区分配给当前所需要的进程。 这个动态分区分配算法
再加一个章节中,我们再来详细的讲解。
3、如何进行分区的分配和回收操作?
回收分为了几种情况:
情况一
:回收区的后面有一个相邻的空闲分区,如图:
假设现在我们需要回收掉进程4
,但是进程4后面有一个空闲的分区,所以空闲分区表会发生以下的变化:
我们可以看到,分区1号中的分区大小:由之前的10变成了14、起始地址也发生了改变,在这种情况,会把两个相邻的空闲分区合并为一个。
如果是回收区前面有一个相邻的空闲分区,那么也是采用同样的方式,两者合并成一个空闲分区。
情况二
:如果说回收区前后都有一个相邻的空闲分区,如图:
那在这种情况下,空闲分区表会发生如下变化:
当进程4移除之后,会把三个空闲空间,都合并成一个。
情况三
:在回收区前、后都没有相邻的空闲分区,那么当进程4移除后,会在空闲分区表中新增一条数据来记录分区。
动态分区分配有什么缺点吗? 缺点当然有的,动态分区分配虽然没有内部碎片,因为是根据进程所需来分配空间,所以不存在内部碎片问题,但是会存在外部碎片。
外部碎片是指:内存中的某些空闲分区由于太小了而难以利用。 举个例子,有一个 1 M 的进程使用完内存后释放了,然后在后续的进程中,1 M 都不能满足需求,所以导致这个 1 M 的空闲内存一直无法被利用,从而产生外部碎片。
那有解决办法吗? 当然有,如果内存中空闲空间的总和,可以满足某些进程的需求,但是由于进程需要一块连续的内存空间,因此这些外部碎片
不能满足进程的要求,在这个时候就可以通过紧凑(拼凑)
技术来解决外部碎片的问题。
紧凑
技术就是把一些外部碎片
合并起来,从而获得一块连续的内存空间,这样就解决了外部碎片
的问题。