操作系统-内存管理
内存管理的目标:
-
实现内存的分配和回收
-
合理的分配内存空间,提高内存利用率,提高内存访问速度
存储器的层次结构
速度由快到慢,容量由小到大,价格由高到低
寄存器->L1高速缓存 -> L2高速缓存 -> 主存储器 -> 本地二级存储 -> 远程二级存储(web/ftp)
特点:每个层级的存储器都保存来自下一级存储器的信息
分类:
-
其中位于CPU内部的是:寄存器->L1高速缓存 -> L2高速缓存
-
其中统称为内存的是:寄存器->L1高速缓存 -> L2高速缓存 -> 主存储器
-
其中统称为外存/辅助存储的是:本地二级存储 -> 远程二级存储(web/ftp)
局部性原理
定义:在一段时间内,程序的执行仅限于某个部分,相应的,它所访问的存储空间也局限于某个区域
分类
-
时间局部性
- 程序的执行仅限于某个部分(某几条指令)
- 某指令一旦被执行,不久之后该指令将再次被执行
-
空间局部性
- 程序所访问的内存仅限于某个部分,
- 若某个单元的内存被访问,则附近的单元将很快被访问
程序的链接
静态链接
含义: 程序被编译后会变成一个一个的独立模块(比如用到的各种库),在运行前,需要使用链接程序将目标模块链接成一个完整的装入模块
特点:运行速度相对快,但占用内存更多
链接程序的具体任务
- 链接程序的任务
- 对逻辑地址进行修改
- 链接程序的任务2
- 变换外部调用符号
- 外部认为程序依然是整体的,所以使用的是Call,但是现在程序被分成不同模块,所以链接程序需要将外部的call变换为JSR(跳转至子程序)
动态链接
含义:可将目标模块的链接推迟到这这写模块中的函数被调用时才进行;
特点:运行速度相对慢,但是可以节省内存
程序的装入
连接程序完成连接后得到一个装入模块,装入程序负责将这个装入模块装入到内存中
绝对装入方式
编译时产生物理地址的目标代码
重定位装入方式
- 可重定位装入方式(静态重定位) ,编译时地址是逻辑地址, 装入时通过重定位转换为物理地址
- 动态运行时装入(动态重定位),程序执行时通过重定位转为物理地址
实际地址 = 逻辑地址 + 物理其实地址
连续分配存储管理方式
单一连续分配
任何时刻主存储器最多只有一个作业
固定分区分配
- 将内存分为固定大小的若干个分区,每个分区可以且仅可以装入一个作业
- 根据系统不同,分区大小可以是相等也可以是相等的
- 每个分区有上限寄存器和下限寄存器,统称为界限寄存器,用于保护内存
- 维护一个
固定分区说明表
用于记录分区的使用情况
动态分区分配
- 分区大小不是预先固定的,而是按照作业的实际需求来划分的
- 分区的个数也不是预先固定的,而是由能装入的作业数决定的
- 维护一个
空闲分区表
,用于记录当前可用的分区信息
-
与空闲分区表功能相同的还有另一种叫做
空闲分区链
-
本质是一个双向链表,每个节点包含一个指向前一个和一个指向后一个分区的指针,以及一个保存可用分区起始地址和长度的数据域;
-
动态分区分配算法
首次适应算法
- 空闲分区链以地址递增的顺序链接,从链首开始查找直至找到第一个满足条件的分区
- 从该分区中划出一块内存给进程,剩下的分区信息仍然留在空闲链中
- 该方式的不足
- 外部碎片,分配后剩下的一点点留在分区链中,由于空间较小,无法被有效利用
- 内部碎片已经分配个某个进程的空间,但进程不需要那么多,空闲了一部分
循环首次适应算法
- 唯一与首次适应算法不同的就是,维护了一个分区指针,每次分配完成,该指针往后移动一个位置;
- 该方式可使得空闲区分布较均匀,但是依然会产生碎片
最佳适应发
- 每次分配前需将分区链节点按照空闲空间大小从小到大排序
- 遍历分区链,查找第一个满足条件的分区分配给进程,
- 该方式可使得每次分配都能尽可能找到与进程需求最接近的分区,减少碎片产生,提高利用率
动态分区分配流程
设使用最佳适应算法,流程已经介绍不在啰嗦
- 对分区链按照大小升序排序
- 遍历分区链在找到可用分区后,从分区中划出区域给进程
- 更新分区链信息
例:设找到的分区起始位置为S,长度为L, 进程需要的大小为N
-
分配完成后,新的起始位置为:S + N, 长度为L - N
-
重新对分区链按空间大小升序排序
动态分区回收流程
- 释放一块连续的内存区域
- 如果被释放的区域与其他空闲区域前后相邻则将前后相邻的分区合并,无论在前在后
- 如果没有相邻的,则创建新节点存储分区信息
- 修改分区链信息
例:
-
设释放的区域起始地址为A,长度为L
-
判断否相邻:设已有空闲分区起始位置为X,长度为Y
- 若 X+Y == A ,则表示前面有相邻, 则合并后空闲分区起始地址为X,长度为Y + L
- 若 A+L == X,则表示后面有相邻,则合并后空闲分区起始地址为A,长度为L + Y