操作系统内存管理详解:功能、原理与分配算法
操作系统内存管理详解:功能、原理与分配算法
一、内存管理主要功能简介
1.1 内存分配
内存分配就像是给每个来到游乐场的小朋友分配一个玩耍的区域。操作系统负责把计算机的内存(就像游乐场)划分给各个程序(小朋友)使用。当一个程序需要运行时,操作系统会给它分配一块合适的内存空间,确保它有足够的地方存放数据和指令。当程序结束或者不再需要那么多内存时,操作系统还会回收这些空间,以便给其他程序使用。
1.2 地址映射
地址映射就像是给每个房间编上门牌号。在计算机中,程序用逻辑地址(就像是容易记住的房间号)来访问数据,但计算机的硬件实际上使用的是物理地址(真实的房间位置)。地址映射就是将程序中的逻辑地址转换成内存中的物理地址的过程,就像是快递员根据门牌号找到实际的房间位置一样。这样,程序不需要知道数据具体放在内存的哪里,操作系统和硬件会帮忙找到。
1.3 内存保护
内存保护就像是给每个房间安装锁,确保只有房间的主人才能进入。在计算机中,这表示操作系统会确保每个程序只能访问自己分配到的那部分内存,不能随意读写其他程序或操作系统的重要数据(地址越界、操作越权)。这样可以防止程序错误或恶意行为破坏系统的稳定性和安全性。
1.4 内存共享
内存共享就像是几个好朋友一起看一本书。在计算机中,多个程序可以共享同一段内存区域,这样可以节约内存资源,提高效率。例如,多个进程可能需要访问同样的库文件或数据,操作系统会让这些进程指向内存中的同一份数据,而不是为每个进程复制一份,这样既节省了空间,又能让进程间通信变得更加高效。(共享内存区内信息,提高内存利用率)
1.5 内存扩充
内存扩充就像是用魔法让小房间看起来像大房子。通过虚拟内存技术,操作系统可以让程序觉得好像有比实际物理内存更大的内存空间可用。当程序使用的内存超过实际物理内存时,操作系统会暂时把一部分不常用的数据移到硬盘上,需要时再调回内存。这就像是把家里的东西暂时放到仓库,需要时再取回来,从而让家(内存)感觉更大。这种方式让计算机能够运行比实际物理内存更大的程序。
二、内存管理
进程运行的基本原理
编译
编译: 源程序经过编译程序的处理生成目标模块(目标代码)。
链接
将各种模块打包成一个完整的程序可执行模块
静态链接:在程序执行前,所有的目标代码文件和库文件被合并成一个单独的可执行文件(不再拆分)。这意味着程序运行时不需要额外的库文件。
装入时动态链接:程序装载时边装载边连接。
运行时动态链接:程序在执行时,需要用到该模块,才加载所需的库文件。这种方式可以让多个程序共享同一份库代码,便于修改与更新,灵活性高。
装载
把可执行程序装入内存
绝对装载:装载模块中的指令地址始终与其内存中的地址相同(只适用于单道程序设计)
可重定位装载:装入时将逻辑地址转化为物理地址
动态运行时装载:运行时将逻辑地址转化为物理地址
地址重定位(地址转换)
静态重定位:由装载程序实现代码模块的装载与地址的转换。
优点:易于实现,无需硬件支持。
缺点:不允许在内存中移动位置,只在单道程序中使用。
动态重定位:由装载程序实现代码模块的装载,不改变程序的逻辑地址。
优点:允许在内存中移动位置,利用率高,便于程序共享。
三、覆盖与交换
3.1 交换
用于解决多程序存在而内存不足问题(内存空间紧张,某些进程暂时换出外存)
外存中具备条件的进程换入内存
时机:有许多程序运行,内存空间吃紧时进行;系统负载降低时暂停(优先换出阻塞、优先级低的进程)
3.2 覆盖
背景:当程序长度超出物理内存总和,或超出固定分区大小,出现永久性短缺,大程序无法进行。
概念:程序执行过程中程序不同的模块在内存中相互替代,以达到小内存执行大程序的目的。
包含一个“固定区”,若干个“覆盖区”
固定区存放程序的引导代码、常驻模块(如中断处理程序)、全局变量(如果设计上选择不覆盖)、主控循环以及其他在整个程序生命周期中都需要频繁访问的代码和数据结构
覆盖区是内存中用于动态替换数据或代码的部分,主要目的是通过复用这部分内存来容纳比物理内存更大的程序。在程序的不同执行阶段,覆盖区会根据当前需要加载不同的模块(比如不同的游戏关卡数据、用户界面模块或特定功能的代码)。
简单解释:
想象一下,你正在编写一个早期的游戏机程序,这个游戏机的内存非常有限,不足以同时存储游戏中所有关卡的数据。为了能让游戏流畅进行,你采取了覆盖技术来管理内存。
游戏分为几个不同的关卡,每个关卡都有自己的背景图像、敌人配置和音乐数据。由于内存不足以同时容纳所有关卡的数据,你设计了这样的策略:当玩家开始第一关时,内存中只加载第一关的所有必要数据。一旦玩家完成了第一关并准备进入第二关,游戏不会立即加载第二关的数据,因为内存已经被第一关的数据占用了。此时,覆盖技术发挥作用——游戏引擎会“覆盖”第一关的数据,用第二关的数据取而代之。这意味着第一关的数据在被覆盖前需要被妥善保存(如果之后可能需要回退到这一关的话),或者如果确定不再需要,则直接释放这部分内存空间。
四、连续存储管理
4.1 单一连续分配
单一连续分配中,内存被分为系统区与用户区。系统区存放操作系统相关数据,用户区存放用户相关数据。内存中只能有一道用户程序,用户程序独占整个用户区空间。
优点:无外部碎片,实现简单。
缺点:只能用于单用户、单任务的操作系统中,有内部碎片,存储器利用率极低。
4.2 固定分区管理
定义:固定分区可以分为分区大小相等、分区大小不等两种。内存空间被划分成数目固定不变的分区,各分区大小不等,每个分区只装入一个作业,多个分区都装有作业可以并发执行。
分区大小相等:缺乏灵活性,适用于一台计算机控制多个对象。
分区大小不等:增加了灵活性,满足不同大小的进程需求。
优点:实现简单,无外部碎片。
缺点:①用户程序太大时,作业无法装入内存。②会产生内部碎片,存储器利用率低。
4.3 动态分区分配
定义:动态分区分配不会预先划分内存,而是在作业在装入内存后,根据进程所需要的大小动态地建立分区。
动态分区使用的数据结构
多个分区满足需求,选择哪个分区进行分配:参考动态分区算法
动态分区分配没有内部碎片,有外部碎片。
五、动态分区分配算法
5.1 最先适应分配算法
该算法顺序查找空闲区,直到找到第一个能满足长度要求的空闲区为止。为进程分配内存空间时从低地址部分空闲区开始查找。
可使高地址部分少用,保持较大空闲区,利于大作业装入。内存高、低分区利用不均衡,回收分区有困难。
5.2 下次适应分配算法
该算法从未分配区的上次扫描结束处顺序查找(地址递增)未分配区表或链表,找到第一个能满足长度要求的空闲区。
缩短平均查找时间,无论高、低地址部分的空闲分区都有相同概率被使用,可能会导致无大分区可用。
5.3 最优适应分配算法
该算法扫描整个未分配区表或链表,从空闲区中挑选一个能满足用户进程要求的最小分区进行分配。通常把空闲分区按容量递增次序链接。
内存利用率好,但是会产生很多外部碎片,查找时间最长。
5.4 最坏适应分配算法
该算法总是挑选一个最大的空闲分区分割给作业使用,通常把空闲区按长度递减顺序排列。
查找效率高,但是较大的连续空间被快速用完,后续如果有“大进程”到达,没有内存分区可用。
5.5 分配算法总结
最先适应分配算法简单、快速,实际操作系统中使用最多,其次是下次适应分配算法和最优适应分配算法。
六、名词解释
外部碎片:空闲分区(内存未分配)太小(过于零散)难以利用。
在内存管理中,外部碎片指的是那些分散在内存中的小块空闲空间,它们可能加起来很大,但是由于每个都太小,不足以分配给任何正在请求内存的进程。这通常发生在动态分区分配方式中,随着进程不断分配和释放内存,空闲空间逐渐变得零散。
内部碎片:分配给某进程的内存中未被利用的部分。
在计算机内存管理中,如果为一个进程分配了一块大于它实际需要的内存空间,那么超出它实际使用部分的空间就是内部碎片。比如,一个进程只需要6KB内存,但操作系统按照固定大小分配给了它10KB,那么这多出来的4KB就是内部碎片