内存管理
程序执行过程
编译
- 源代码-模块
链接
-
链接各个模块及其相应库函数
-
静态链接
- 运行前,一次性将全部的 库函数、模块 链接起来
-
装入时动态链接
- 在 装入 步骤的时候进行边装入边链接
-
运行时动态链接
- 运行时需要哪个模块,那时候才进行链接
-
装入
-
装入内存运行
-
绝对装入
-
可重定位装入
-
静态重定位
-
动态重定位
-
-
逻辑地址
- 相对地址
物理地址
- 绝对地址
扩充内存
覆盖
-
用户空间
-
一个用户区
- 不会进行程序段的调入调出
-
若干个覆盖区
- 会进行程序段的调入调出
-
-
覆盖是指在一个程序的内存空间上开辟一段空间,这个空间叫做覆盖区,存放那些不经常调用的段,每次调用谁,再把谁装入覆盖区,不用的时候,就在外存(所以覆盖区的空间大小是所有段的最大值)
-
对用户不透明
交换
-
文件区
-
交换区
- 存放换出的进程
连续分配
连续分配
-
单道连续分配
-
系统区
- 低地址
-
用户区
-
一直按照地址递增顺序分配
-
优点
- 无外部碎片
-
缺点
- 有内部碎片
-
-
多道固定连续分配
-
分区大小相等
- 适合一台计算机控制相同对象的场合(炼钢炉)
-
分区大小不等
- 增加了灵活性
-
优点
-
实现简单
-
无外部碎片
-
-
缺点
-
有内部碎片
-
不一定能够载入一个大程序,还是需要使用 “覆盖” 技术
-
-
-
多道动态连续分配
-
数据结构
-
数组
-
链表
-
-
相邻空闲内存区间可以使用 ”紧凑“ 技术进行合并,解决外部碎片
-
内存分配算法
-
首次适应算法(First Fit)
- 按照地址递增的顺序,找到第一个满足的分区
-
最佳适应算法(Best Fit)
- 按照容量递增的顺序,找到第一个满足的分区
-
最坏适应算法(Worst Fit)
- 按照容量递减的顺序,找到第一个满足的分区
-
邻近适应算法(Next Fit)
-
以地址递增的顺序,每次从上一次分配好的地址进行查找,找到第一个满足的分区
-
会产生最多的外部碎片
- 因为大分区也被等概率地使用,最后导致没有大分区可用
-
-
-
非连续分配
-
页式存储管理
-
内存
-
分为大小相等的 ”页框“
- 页框=页帧=内存块=物理块=物理页面
-
-
进程
- 分为大小相等的 ”页面“
-
重要的数据结构 ”页表“
-
存放 进程的 ”页面“ 和实际内存块 ”页框“ 的映射关系
-
(页号,块号)
-
页号(页面号、进程中的)不需要占据空间,数组下标
-
“页框” 的数量就是块号的位数——但是是以字节为单位,所以应该取的是最小的字节数(20bit就应该用3字节)
-
-
页表必须连续存放
-
-
逻辑地址结构
-
页号 = 逻辑地址 / 页面长度
页内偏移量 = 逻辑地址 % 页面长度-
此处的 “页号” 是进程中的页面号
-
按位划分,主要是能够知道一个进程中有多少个页面(2n个),而一个页面中又有多少个内存单元(也即一个页面有多大,2m 字节)
-
页号的作用:算出来页号才能找到页表中的对应页表项
-
-
求出页号——根据 “页表” 找到块号——从块的起始地址开始+页内偏移量——找到进程
-
-
“快表”
-
命中——一次访存(快表)
未命中——两次访存(页表+内存) -
不使用快表——两次访存(页表+内存)
-
局部性原理
-
时间
-
空间
-
-
-
两级页表
-
为什么引入?
-
一个页表如果有很多项,需要很多连续的页框,有时可能分配不了
-
一个进程运行时并不是其所有的页表都需要使用到,所以也需要 ”精细化管理“
-
-
页目录表(顶层页表、外层页表)
-
页目录表记录二级页表的存放位置,像一个指针一样,这样就可以使得页表离散存放
-
可以在页目录表中添加一个信息:是否调入内存
这样就可以在需要的时候才将页面调入内存
-
-
怎么转化为物理地址?
- 1.根据一级页号找到一级页表对应的页表项——也即二级页表的存放位置
2.找到二级页表之后,根据二级页号查找对应的物理块号
3.访存
- 1.根据一级页号找到一级页表对应的页表项——也即二级页表的存放位置
-
-
本题中,页面大小为4KB,一级页表0项对应的块号为3,所以应该去341024的地方找二级页表,二级页表是1号页,偏移量为4095,最终地址:341024+4095
- 页表的大小不能超过页面大小(计算题)
- 多级页表访存次数:N+1次
-
段式存储管理
-
逻辑地址结构
-
段表
-
用于映射 段到内存
-
(段号,段长,本段在主存的起始地址)
-
段号决定段的数量
-
段长决定每段的大小
-
-
注意事项
-
以段为单位分配
-
段与段之间不能相邻
-
每段都从0开始编址
-
-
-
-
段页式存储管理
-
先分段,后分页
- 段表只有一个,但是页表可能有多个
-
逻辑地址
-
(段号,页号,页内偏移量)
-
段表:
(段号,段长,页表起始地址) -
页表:
(页号,块号)
-
-
-
找物理地址的步骤
-
1.从逻辑地址中找到段号,判断是否越界
-
2.根据段号,在段表中查找段表项,得出响应页表存储块号
-
3.去相应内存块查找 页表项,得到真实物理地址
-
4.访存
-
-
虚拟内存
概念
-
局部性原理
-
传统存储管理方式
-
一次性
- 每次运行作业的时候会将其全部载入内存
-
驻留性
- 不管作业中的进程会不会被使用,都在内存中保持驻留
-
-
虚拟存储器
-
多次性
- 允许作业中的进程分多次调入内存
-
对换性
- 作业中的进程无需长期驻留,需要时换入,不需要时换出
-
虚拟性
- 看到的内存 >> 实际的内存(作了内存映射)
-
请求分页管理
-
与基本分页管理的区别
- 能够在需要时才将页面调入
所以需要增加字段来表示调入没有
- 能够在需要时才将页面调入
-
请求页表
-
(页号,状态位,修改位,访问字段,外存地址)
-
状态位——是否调入内存
-
访问字段——记录最近的访问信息(访问次数,上次访问到哪里了)
-
修改位——记录调入内存后是否有修改,有的话需要将其写回外存
-
外存地址——记录在外存存放位置
-
-
子主题 2
-
-
缺页中断机构
-
当所需要的页面不在内存中,会触发缺页中断,当前进程阻塞,调入页面完成后才会继续运行
-
是由当前进程发出寻找缺页页面的指令,所以是内中断
-
一个进程执行期间可能引起多次中断
-
-
寻址步骤
-
1.根据逻辑结构中的 “页号”,判断是否越界,然 后先去快表找
-
2.快表没找到,去请求页表找
-
3.找到后,核对状态位,如果未调入内存,产生中断,更改状态位,然后根据页表项中的外存地址找到存储块,调入内存
- 如果内存不厚,需要进行 “交换” 页面
-
-
页面置换算法
-
最佳置换(Optimal)
-
每次淘汰的是之后最长时间不被使用的页面
-
无法实现
-
最低的缺页率
-
-
先进先出(FIFO)
-
每次淘汰的是最早进入的页面
-
产生Belady异常
- 分配的内存块增多,但是缺页次数增加
-
-
最近最久未使用(LRU)
- 从当前开始往前数,最早被使用的块应该被淘汰
-
时钟算法(CLOCK,NRU)
-
淘汰的就是未访问过的,循环访问
-
1.循环扫描各页面,先淘汰未访问过的
-
2.在扫描的同时,将扫描过的访问位都置为 未访问过
-
3.如果扫描一遍都没有未访问过的,那就将第一个扫描到的页面淘汰(此时这个页面已经是未访问的状态)
-
-
改进的时钟算法(改进NRU)
-
淘汰的尽量是未访问过、未修改过的
- 因为未修改过的页面,就可以不用将其写回外存,直接替换即可
-
1.同样是循环扫描,以(访问位,修改位)进行,0表示未访问/未修改
-
2.首先淘汰(0,0)
-
3.然后淘汰(0,1),扫描的同时,将扫描到的访问位置为0
-
4.然后淘汰(0,0)
-
5.最后淘汰(0,1)
-
-
-
页面分配策略
-
驻留集
- 请求分页存储管理中,为进程分配的内存块集合
-
工作集
- 一段时间间隔里,进程实际访问页面的集合
-
页面分配、置换策略
-
固定分配
- 运行前分配好
-
可变分配
- 运行时如果缺页,就找空闲块分配
-
全局分配
- 缺页时,可以将其他进程的空闲块分配至缺页进程
-
局部分配
- 缺页时,只能从自己进程中找空闲块
-
-
何时调入页面
-
预调页
- 进程运行前
-
请求调页
-
进程运行时调入
-
发现缺页时才调入页面
-
-
-
何处调入页面
-
对换区内存充足时
- 内存——对换区
-
对换区内存不足
- 如果调入的页面不需要修改,外存的文件区——内存
-
-
抖动
-
页面频繁调入调出的现象
-
原因是分配给进程的内存块不够
-
-