操作系统内存管理

内存作为重要的系统资源,是操作系统重点的管理对象。操作系统中提供的对于内存的管理策略可以从两个方面来分析:

1.内存的利用率

如何提高资源的利用率当然是系统的重头任务,当前很显然的方式就是多道程序并发运行,避免内存空间的浪费,这也是操作系统所选择的方式。为了能够使内存中同时存在多个进程,需要给进程分配一定的独立空间(先不考虑共享内存、纯代码之类的东西),分配方式有许多,例如将进程分配在连续内存空间的固定大小区域(固定分区),或者根据进程所需大小分配的内存上连续的区域(动态分区),以及逻辑上具有连续概念的按照程序段分配内存(分段),或者直接将程序撒布在内存的不同地方,即按页分配(分页)。

2.内存的逻辑扩展

所谓的内存扩展其实就是对内存的重复利用,呈现出来的表象则是可以使用的内存空间比实际内存空间略大。例如内存覆盖,重复利用自己的一亩三分地,需要程序员指定覆盖结构,不透明的东西因为“懒”的程度不够,所以基本已经不用了,相同的思想现在主流为虚拟技术(其实说是相同的思想有点牵强,虚拟和覆盖虽然都是满足部分加载即可运行,内存不够吃老本(某些页面分配策略中也可以使用操作系统的空闲页面),但是虚拟技术更年轻,覆盖所处的时代没有分页,没有局部性原理的应用,所以严格来讲算是部分思想相同)。交换技术则是把刚运行过的进程(注意是进程,而不是刚调用过的页面,不然就是跟时间局部性对着干了)换出内存,也算是重复使用内存空间。

内存管理所提供的功能有:

1.内存分配与回收

内存资源属于系统资源,创建进程分配资源,也就是进行内存调度时是由操作系统来完成的工作。

2.内存扩充

既然不给加物理内存,那说白了就是进程使用的逻辑地址扩充,扩充的越多,地址变换就越复杂,甚至造成的影响使得实际运行效率更低,所以做事情都要讲究个度。

3.内存共享与保护

对于可重入内存区,即不能修改的内存区域,自然是可以共享的,但是对于那些能够被修改的部分,在多道程序并发中则需要做好同步处理,这个意思有点像多进程环境中对于临界区资源的控制访问,避免存在数据结构不一致问题。

4.地址变换

地址变换简单说就是完成逻辑地址到物理地址的转换。对于单道程序环境,也就是说除了操作系统占据的内存之外,其他内存都交给一个进程使用的情况,程序中可以直接使用物理地址,在加载程序创建进程时,无须进行地址变化。不过讲道理,程序中使用的都是逻辑地址,无论使用的是连续内存分配或者不连续内存分页技术,都需要在加载程序时作地址变换,因为多道程序环境下不能确定使用的内存是空闲的内存,还是把别的进程换出后空出来的内存,又或者根本就是对自己的内存页做了替换。

由上面几个所列的功能可以看出,内存管理多多少少都与最上面提到的两个方面存在关系,至于内存共享与保护则根本就是在提高内存利用率的方式中添加的访问规则。

以连续内存和非连续内存两个方面来说

连续内存

连续内存是指在创建进程时,给其分配的内存资源是一段连续的物理内存。

单道程序连续内存

内存中除了操作系统占据的空间之外,其余都分配给程序使用,因为系统中除了操作系统之外,只有一个运行的进程,所以实现上自然很简单。如果是放到现在来看,内存的使用存在极大的浪费,不过如果在某些特定使用的环境中,整个系统的资源只需要维持一个特定任务的运行,而且内存空间相对于要运行的进程来说并不是很大,甚至还需要覆盖来保证运行,则看起来就挺合理了。

固定分区

将内存中有效部分分成一个个固定大小(大小可以相同也可以不相同)的分区,也就是内存块,每个进程使用一个块。以这种方式实现对内存资源的划分,可以避免外部碎片的产生。但是分区大小的设置跟进程所需大小没有什么关系,结果就是分区内可能存在碎片,也就是分区太大,用不完;还有就是分区太小,导致程序的运行中需要不断的使用覆盖技术,如果分区小到不能维持进程运行需要的最小数据量,则进程无法执行;最好的使用场景就是所使用的进程都是类型相同的,也就是在分区大小都相等的情况下,可以使得每个分区刚好匹配一个进程,从中也可以看出该方式适应度较差,不符合多进程并发的复杂环境(虽然它分成一块块的目的就是为了多道程序并发运行)。

动态分区

相对于固定分区不考虑程序的特性而进行分区,动态分区是在加载程序时,根据程序所需的大小进行分区,满足程序可运行。但是在不断的分配过程中,可能存在外部碎片,也就是当内存分配到最后,剩余的空间小到不足以分配给待执行的进程,以及使用交换技术将已经运行过的程序换出后,将内存分配给换入的进程时,最终剩下的部分分区碎片。所以对于这些散布在内存中的碎片,需要进行整合,提高利用率。

分区分配算法

在加载程序创建进程分配内存资源时,对动态分区方式的分区分配策略有:

最先适应(first fit):按内存顺序从头开始找,第一个满足进程需要的分区即可。此种方式分配多次之后的结果就是前面内存分的散散的,但是每次仍然从头开始查找,增加了遍历消耗(相比较内存合并而言这倒是很小的消耗)。

临近适应(next fit):按内存顺序查找,只不过是从上次找到的位置开始接着查找,第一个满足需求的分区。看起来这种方式好像要解决最先适应算法的查找消耗问题,但是基本也是瞎整,每个进程需要的空间大小都是不同的(上面固定分区提到的类型相同的进程除外),直接导致的结果就是太大程度上忽略了前面的内存,比如前面执行完毕进程换出,分配内存却是从之后开始查找的。

最佳适应(best fit):保存一个内存大小递增排序表,从小开始找到第一个满足需求的分区。最佳适应算法的外部碎片问题比最先适应还要严重,因为从最佳适应的策略中可以看出,相比较与最先适应找到第一个满足的,然后拆成两份(前一份使用,后一份就是碎片,如果碎片不是很小很碎,或许可以留给后面某个进程使用),最佳适应则是故意产生外部碎片,每一次查找分区都产生一个小小碎片,不过最佳适应有效的保留了大空闲分区,可以满足可能出现的较大需求的进程,而不是进行内存合并。

最坏适应(worst fit):保存一个内存大小递减排序表,从大开始找到第一个满足需求的分区。最坏适应刚好反过来,首先把最大的用来,到后面进行内存合并的次数可能较多,因此效率不咋地。

非连续内存

非连续内存也就是传说中的内存分页了,这个页相对于之前说的分区来讲那当然是很小的(也不能太小,不然页表项太多,存个页表都要挺大内存,虽然有二级页表,但地址变换、查询内存次数太多,虽然依据局部性原理有快表,但仍然可能没有命中,虽然命中率很高。。。),但是概念不同,分区意思是要把整个进程需要的内存都分配出来,分页只是表示一个小小块,面向对象不同。

分页存储

内存分成固定物理页大小,程序编写面向逻辑页地址,在程序加载时进行地址变换,至于如何变换,自然需要伟大的地址映射工具--页表来完成(页表也起到检查是否存在地址越界问题),变换形式如下:



这里就存在了刚刚提到的一个问题,如果进程是面向整个内存空间编址的,则页表需要保存对整个内存中所有页的映射关系,页表项太多导致页表太大问题,根据相同的思想,对页表分页,然后另建一个页表保存对上一个页表的各个页的映射关系,即二级页表机制。内存中只保留第一级页表,需要时再加载对应的第二级页表。

段页式存储

该方式是将程序按照程序结构分成各个段(为了共享方便,逻辑分段,并不是在物理内存中划分具体的段,只是为了共享而产生的一个概念),在段内再进行分页,相当于先进行一个地址变换,找到逻辑上所处的段,然后段内就跟正常的页地址变换一样,找到实际的物理地址,不过就是加了一个到段地址的变换而已。

至于段地址的变换,跟页地址过程相同,多了一个段表,一方面做地址映射,一方面做越界检查,变换形式如下:




请求(虚拟)分页/段页

虚拟技术之前已经提到过,就是在逻辑地址上进行扩展,使得程序可以面向逻辑地址编写(也算是抽象地址的概念了),在加载时转换为物理地址。所依赖的主要有两个方面,一是进程可以在不加载全部的情况下执行,二是局部性原理。

进程的执行不必等待所有内容全部加载进内存,这也是覆盖技术的支撑。以此为前提,在查找指定页时,发现对应页面不在内存中(通过页表判断,需要给页表增加额外的功能,而不只是越界检查和地址变换),则发出缺页中断(主动中断),调用中断处理程序加载页面或者替换页面(具体就要看页面置换策略了),更新页表。

页面置换策略

1.最佳置换(OPT)

置换出去的页面都是最久用不到的,这个策略很明显是理想情况下的,局部性原理也只是根据之前的行为预测可能将要发生的行为,而预测一段时间之后可能不发生的行为则属于理想情况了。

2.先进先出(FIFO)

这种方式实现很简单,就是将置换进来的页面排队,先来的先走,没有考虑哪些页面被频繁使用,所以整个操作带有随机性,可能把接下来要用的页面给换出去了。

3.最近最久未使用(LRU)

根据名字就可以看出,置换出最久时间没有访问过的页面,需要标记页面最近被访问的时间,然后在需要置换时把最旧没被访问的页面换出去,可能存在的问题就是偶尔被访问的页面把真正需要的页面替换出去。MySQL中提供了一个中点插入策略可以作为参考:

将LRU维持的页面分为两部分:hot表和warm表,当页面读入时,放到warm表的尾部,hot表的头部,如果接下来命中一定次数,则晋级升到hot表,如果一定时间没有被访问,则降到warm表,需要置换时,从warm表的头部置换出页面,通过设置warm表和hot表的比例以及设置两个表的降级速度,来避免偶尔被访问页面将真正需要页面替换出去的情况。

总结

内存的管理,最基本的目标就是提高内存资源的利用率,在满足多道程序并发的同时由要保证内存访问的安全性,在选择多道程序下的内存分配策略时,又要考虑降低其他操作带来的性能的影响,例如地址变换、分区查找、页面置换以及碎片整理等。


参考:http://c.biancheng.net/cpp/u/xitong/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值