【操作系统】存储器管理
【操作系统】存储器管理
目标:
-
确保计算机有足够的内存处理数据
-
确保程序可以从可用内存中获取一部分内存使用
-
确保程序可以归还使用后的程序以供其他程序使用
一、存储器的层次结构
二、程序的装入和链接
用户程序要在系统中运行,必须先将它装入内存,然后再将其转变为一个可以执行的程序,通常要经过下面的步骤:
- 编译:编译程序对用户源程序进行编译,形成若干个目标模块
- 链接:有链接程序将变异后形成的一组目标模块以及它们所需要的库函数链接在一起,形成一个完整的装入模块
- 装入:由装入程序将装入模块装入内存(也就是运存)
1、程序的装入
先介绍一个无需进行连接的单个目标模块的装入过程,有以下三种方法:
①绝对装入方式
当计算机系统很小,并且只能运行单道程序的时候,完全有可能知道程序将驻留在内存的什么位置。
即用户程序编译之后,将产生绝对地址的目标代码,然后有CPU去取指令执行。
程序中所使用的绝对地址既可以在编译或者汇编的时候给出,也可以由程序员直接复制。
②可重定位装入方式
在多道程序环境下,编译程序不可能知道经过编译之后所得到的的目标模块应该放在内存的什么地方。
因此,对于用户编译所形成的若干个目标模块,它们的起始地址通常都是从0开始的,程序中的其它地址也都是相对于起始地址计算的。
此时,不可能再用绝对的方式装入,只能用重定位的方式,它可以根据内存的具体情况将装入模块装入到内存的适当位置。
通常,把在装入时候对目标程序中指令和数据地址的修改过程称为重定位,地址变换通常是在进程装入时一次完成的,以后不再改变,也可以称为静态重定位。。
③动态运行时的装入方式
可重定位装入方式不允许程序在运行时在内存中移动位置。因为程序在内存中的移动,意味着它的物理位置发生了变化,这个时候必须对程序和数据的地址(绝对地址)进行修改后才能运行。
在实际情况中,程序运行过程中在内存中的位置要经常改变。此时就需要动态运行时的装入方式。
此方式是将程序在把装入模块装入内存之后,并不立即把装入模块中的逻辑地址转换为物理地址,而是把这种地址转换推迟到程序真正要执行的时候才进行。因此,装入内存后的所有地址都仍是逻辑地址。
2、程序的链接
源程序编译之后,可以得到一组目标模块,链接程序可以将这组目标模块和他们所需要的库函数装配成一个完整的装入模块。
①静态链接
在程序运行之前, 先将各个目标模块及它们所需要的库函数链接成一个完整的装配模块,以后不再拆开。
②装入时动态链接
目标模块在装入内存时候,采用变装入边链接的方式。
③运行时动态链接
在程序运行的时候,才对具体执行模块所需要的库函数进行链接。
三、内存分配与回收
1、内存的分配
①单一连续分配方法
-
只能在单用户、单进程的操作系统中使用。
-
把内存分为系统区和用户区两个部分
②固定分区分配
- 是支持多到程序的最简单的存储分配方式
- 内存空间被划分为若干固定大小的区域
- 每个分区只提供给一个程序使用,互不干扰。
③动态分区分配
- 根据进程实际需要,动态分配内存空间。
- 涉及到相关的数据结构和分配算法。
2、动态分区分配的数据结构
①空闲表
- 如果是0,表示未被使用,如果是1表示已经被使用。
②空闲链
- 把所有的空闲节点,首位相连接起来,双向链表。
- 可以合并空闲的节点2和结点3
- 节点需要记录内存容量
3、基于顺序搜索的动态分区分配算法
①首次适应算法(FF)
- 分配内存时候,从开始顺序查找合适的内存区(空闲链)
- 若没有合适的空闲区,则该次分配失败。
- 每次从头部开始,使得头部地址空间不断被划分
- 改进可以用循环首次适应算法(NF):从上一次首次适应的末尾开始。
②最佳适应算法 (BF)
- 要求空闲区链表按照容量大小排序
- 遍历空闲区链表找到最佳合适空闲区
- 避免大材小用
③最坏适应(WF)算法
- 总是挑选最大的空闲区,分割一部分给作业使用,以至于存储区中缺乏大的空闲分区。
4、基于索引搜索的动态分区分配算法
当系统很大的时候,系统中的内存分区可能会很多,相应的空闲分区链就可能很长。
①快速适应算法
- 要求有多个空闲区链表
- 每个空闲区链表存储一种容量的空闲区
- 在内存中设立一张管理索引的表,一一对应。
②伙伴系统
无论已分配分区或者空闲分区,其大小均为2的k次幂。
③哈希算法
利用哈希快速查找的有点,以及空闲分区在可利用空闲区表中的分布规律,建立哈希函数,构造一张以空闲分区为关键字的哈希表。
5、动态可重定位分区分配
- 紧凑:
- 连续分配方式的特点是:用户程序必须被装入连续的空间。
- 后果是,内存空间将会被分割许多小的分区,会产生碎片,造成大作业无法装入
- 通过紧凑的方法,将所有的作业移动,使得它们邻接,可解决问题。但是程序的物理地址也发生了变化
- 动态重定位:
- 进行了紧凑之后,执行到下面的指令,只需要逻辑地址和物理地址的转换即可。
6、内存的回收
- 情况①:
- 只需要把空闲区1的容量增大
- 情况②:
- 回收区和空闲区合并,形成新的结点,使用新的空闲区地址。
- 情况③:
- 三个都合并,使用空闲区1的地址
- 情况④:
- 创建新的空闲节点
四、分页存储管理方式
连续分配方式会形成许多碎片,虽然可以使用紧凑方法,但是代价太大。如果允许将一个进程直接分散地装入到许多不相邻接的分区中,便可以充分的利用内存空间,而无需进行紧凑。
基于这一个思想,产生了离散的分配方式。
1、页式存储管理
- 页面:
- 将进程的逻辑空间分成若干个也,并为各页加上编号,从0开始。
- 相应地,也把物理地址空间分成若干个块,同一也给它们加上编号。
- 在为进程分配内存的时候,以块为单位,将进程中的若干个页分别装入到多个可以不相邻接的物理块中。
- 由于进程的最后一页经常装不满一块,而形成了不可利用的碎片,称之为“页内碎片”。
-
页面大小
- 通常是512B ~ 8K
-
页表
- 地址结构
- 缺点
- 如果程序有一段连续的逻辑放在了不同的页中,会降低程序执行的效率。
2、段式存储管理
- 将进程逻辑空间划分成若干段(非等分)
- 段的长度由连续逻辑的长度决定(程序的逻辑长度)
- 主函数MAIN、子程序段X、子函数Y等等
3、小结
4、段页式存储管理
逻辑图
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!