在将一个可执行代码通过某种装入方式(静态或动态)装入内存,使其变为一个动态的进程的过程中,我们的内核使用和种方法来管理该进程所要使用的内存的呢?接下来我就为大家一一道来
1.早期的连续分配方式
在60-70年代,那会我们的计算机计数还不发达,所以每创建一个进程,我们都得先在内存中为其分配好一块足够其使用,并前必须是连续的内存,这种方法在我们先在操作系统中当然以不在使用,但它的原始思想我觉得还是值得我们学习一下的
在这种必须要给一个进程分配连续的内存的大环境下,共有如下几种分配方式
(1)单一的连续分配
这是最原始的一种方式,只能用于单任务单用户的系统,此种方式大致意思为,对于一台计算机中的一块内存,除了内核所占用的内存外,剩下的内存每次只能分给一个运行的进程
(2)固定分区分配
显然(1)中的内存分配方式过于低效,于是起好点的固定分区分配模式就出来了。其主要思想是将(1)中的大块内存划分为多块大小不等(但固定)的小块分区,每个分区块每次只能装载一个进程,这样便可同时容纳多个进程运行了,要实现这种内存分配方式,需要我们解决如下几个问题
划分分区的方法
(1)分区大小相等
这种方式很好理解,使每个分区的大小相等,这种方式的额灵活性并不高,当进程很小是,每块内存块会有很大的浪费
(2)分区大小不等
为了客服(1)中的等大小所产生的不灵活性,我们可以把分区划分成大小不同的,这样我们可以更具进程的大小把它装入适中的分区块中
内存分配
针对(2)中的分区方式,我们可以给不同大小的分区块排个大小,,并建立一张分区的使用表,表中包括每一个分区的起始地址,大小,使用状态等,当有程序需要装载时,分配程序检索该表,找出满足要求的内存快分配给该程序
(3)动态分区分配
动态分区分配相比上述固定分区分配中的分区分配大小不等方法主要增加了如下俩点
1)进程在链表中选到某个空闲分区块时,会把该分区块中超过自己使用大小的部分切割下来,继续链在链表中供其他进程使用
2)由于1)中的切割操作,所以当我们进程结束时,需要对其使用后的内存进行回收
要实现动态分区分配,主要实现如下几个内容就可以了
(1)分区分配中的数据结构
我们可以用一个链表将空闲分区串起来
(2)分区分配算法
1.首次适应算法FF
FF算法中链表是按空闲块的地址递增顺序排序的,我们每次找满足要求的内存块时,到会从链表头开始便利。这种做法的特点是,链表靠前的块会被切割的很小(碎片化),链表靠后的位置会存在大块
2.循环首次适应算法
该算法相比FF主要区别为每次遍历的起点都为上次遍历的重点,当遍历到链表尾部时,在从头开始。该算法避免了一种将链表前面的块过于碎片化,但是缺点是没有大的块了
3.最佳适应算法
最佳适应算法相比上述1中算法最大的区别就是,链表按分区块的大小升序排序,该算法的优点是每次找的分区块总是大小最合适的,但这种优点会使我们切割下来的碎片过小而难以利用!
(3)回收内存
由于进程所用的内存几乎都是以切割分区块的方式获得的,所以在回收进程用完的内存时,可能有如下3种情形
1.回收区与插入点的前一个块相连,此时将回收块与前一个分区合并,不必为回收块新开节点
2.回收块与后一个分区相连,此时将后一个块与回收块合并,给回收块新开一个节点
3.回收块同时与前后节点相连,此时将三个分区合并
(4)对换
在多程序运行情况下,可能有部分进程处于阻塞状态(我所接触的可能造成阻塞状态的方式有,读写文件时的阻塞,调用sleep阻塞等),此时这些进程并不占用CPU但却任然占用这内存,可能会导致想用内存的进程在等待它,这很明显是一种缺陷,于是我们就引入了交换的概念
交换是指我们把那些处于阻塞的进程暂时调出内存,然后让等待的进程用这腾出来的内存。这样便可以提升我们的内存利用率了
2.分页存储管理方式
理解了上面介绍的连续分配方式,我想大家也因该看出了它的一个致命缺点,那就是它给每个进程分配的空间都为连续的,这种方式不仅找到合适的内存块不容易而且会产生好多内存碎片,这样我们的内存利用率就不会很高了,于是就产生了分页管理内存的方式来解决上述问题
(1)页面与页表
要理解分页管理是一种什么样的管理方式,我们得首先明白,页(页面)和页表这俩个概念
分页管理是指将一个进程的逻辑地址空间(每个进程的逻辑地址起始都为0)分割成相等的若干片,每个片就是一个页,与每个页等大且一一对应的真是物理内存块叫做页帧,也为我们的操作系统逻辑出来的,所以每个进程的若干页的逻辑地址是相连的,而每个页对应的真实内存页帧却可以是不连续的,那么我们要通过什么方法来管理连续的逻辑页与实际不连续的真实页帧的呢?这里我们又要引入页表的概念。没错我们就是通过为每个进程维护一张页表,通过页表中每一个页表项(页到页帧的映射)来找到每个页对应的页帧在真实内存的什么地方
(2)地址变换机构
地址变换机构指借助(1)中所述的页表来将逻辑页转换为对应的真实页帧
为了借助页表实现地址转换,我们最好的情况是把每一个页表放入到一个寄存器中,但由于寄存器的数量有限,而我们的页表数却很多,可达几十万之多,所以一般页表都会存储在内存当中。由此就会引发当CPU在存取一个数据是它等先取内存中找到页表,然后根据页号(每个页表中的也都从0开始有个页号)找到页表项,从页表项中获得此页所对应的真实内从的物理号以及大小,然后返回给CPU,CPU根据此信息便可获得真实的页帧的物理地址,之后再次访问内存,获取想要的数据。可以看出在一次取数据的过程中我们俩次进入内存,这种低效率显然不是我们想要的。我们将连续的内存管理改变为页式管理,本来是想提高内存的利用率(的确提高了)但却因此降低了CPU的处理速度,那么我们有什么方案可以解决这一问题呢?
针对上述产生的问题,我们又要引入一个新的概念“快表”,所谓快表其实就是具有缓存功能的高速缓冲寄存器,该缓冲寄存器用于存放当前访问的那些页表,还是上述的访问内存数据的过程,如果有了快表,我们上述的第一次访问内存中的页表过程就变成了在快表中查找是否有需要找的页表,如果有我们就不用千辛万苦的去内存找了,如果这个快表的命中率足够高的话,我们的上述由于页的引入而降低了CPU的处理能力的问题就得到了解决,事实上证明,页表的命准率确实够高!
(3)二级页表
关于为什么要出现二级页表,我们不得不说一下我们现代计算机的逻辑地址空间为(32-64)为,我们以相对简单的32位为例,若采用每页的大小为4kb即2的12次方B,则剩下2的20次方为页数,页表刚好是1M(以一个页表项占1B),由此可以看出每个进程的页表大小为1M而且这1M大小要求是连续的,当多个进程同时运行时,我们的内存分配问题又会因此而遇到了和我们最开始连续分配遇到的内存利用率低的一样的问题,解决它的办法还是我们现在说的办法分页,只不过这个分页的对象是页表,这就是二级页表
3.分段存储管理
分段管理其实和分页管理差别并不大,之所以还要引入分段管理,主要是为了满足用户编程或使用上的方便
(1)引入分段管理的原因
1)方便我们写程序
对于我们程序员来说,分段的引入使我们的编程更加方便,我们的程序可以按照逻辑关系划分为若干段,每个段都有自己的名字和长度,程序中常见的段名有数据段,栈段,代码段等
2)信息共享,由于页是等大小分配的,所以采用分页管理的话我们可能会把一个独立的逻辑信息分到多个页中,例如一个页的大小为4k而我们的程序数据块大小为12k,这样一个独立完整的逻辑信息数据块,就被分成了多个页,共享起来当然麻烦,而我们的段是以信息的逻辑单位为基础的,每一个独立的信息逻辑就是一个段,这样共享起来就十分的方便了
3)信息保护
和2)中一样也是以信息的逻辑单位为基础的信息保护当然也是保护段比较方便
4)动态增长
段在使用过程中可以动态增长,而页却不能
(2)分段的基本原理
前面也说过分段的基本原理与分页基本相同,只不过没个页都有相同的固定大小,而每个段却都有着不固定的大小,页和真实内存的映射关系是通过页表来实现的,而段和真实内存的映射关系却是通过段表实现的这俩个概念原理一样,和页表相同为了不因段表的出现而降低CPU的处理能力,我们同样有增加段表查找能力的高速缓冲寄存器
(3)分页和分段的主要区别
分页和分段由于思想上是一样的,所以有好多共同之处,例如俩这都是采用离散分配的额方式,然后通过地址映射机构实现地址转换,但概念上有如下2点不同
1)页是以信息为基本单位,之所以有分页,就是为了削减内存的碎片,提高内存的利用率,而并不管用户的需要,所以以信息为单位,并不需要管这个信息是不是独立的一种信息,或包含了那些信息等,段则是以信息的逻辑为单位,每一种逻辑上为一种信息的都存放在一个段中,不会像页可能存放在好多页中
2)页的大小固定且由系统决定,而段的大小不固定,大小取决于用户所写的程序
4.段页式存储管理
可以看出段是很适应用户的,但是由于段是以信息的逻辑为单位的,所以可能导致每个段或许会很大,于是我们将每个段划分为若干页,这种段页结合的使用方式就是段页式管理方式
5.虚拟存储器
我们前面介绍的内存管理方式都有一个共同的特点,即运行一个程序时得把它全部加载进内存,这可能有时候会遇到一些问题
例如当一个程序很大,已超过你的内存总量了,那么这个程序是不是就运行不了了,还有有大量程序需要运行,但由于内存不能将他们同时都加载进去(由于内存大小不够大)等
针对上述内存大小不过我们用的问题于是就引入了虚拟存储器这个概念
(1)虚拟存储器出现的先决条件
1.程序在运行时的空间局部性
这是指一个程序在运行到某个位置,接下来执行的代码一般都是在这个位置的周围
2.时间局部性
由于程序中存在循环等情况,所以在某些时间段会固定执行某些代码
(2)虚拟存储器的定义
基于(1)中程序在运行期间的局部性特点,我们在程序运行时也就没不要将程序全部装入,仅需将当前需要运行的部分页装入即可(虚拟存储器是建立在有页式(分段)存储的基础上的),其余部分驻留在磁盘上,程序在运行过程中,如果所访问的页已在内存中,则可继续执行,如果所访问的页找不到即缺页,则程序需要通过os提供的请求页功能将他们调入内存,程序又可继续执行,如果此时内存已满,容不下新调入的页,则利用页置换功能将内存中暂时不用的页调到磁盘中,腾出足够的内存空间,在调入要访问的页。从用户角度看,该系统具有的内存容量,比实际内存大的多
但这只是感觉,是虚的,所以我们称这种存储器为虚拟存储器
由上述可得,所谓虚拟存储器,是具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储系统,其逻辑容量有内存和外村共同决定,运行速度接近于内存
(3)虚拟存储器的特征
1.多次性
多次性是指一个作业被分为多次调入内存,由于在程序运行时,没必要将其一次性都加入,所以我们分多次,用啥调入啥
2.对换性
对换性是指允许在作业运行期间进行换入换出