单道编程环境下,整个内存里面只有两个程序,一个是操作系统,一个是用户程序,用户程序永远在同一个地方开始执行,这样,运行前可以计算出物理地址叫做 静态地址翻译
优点:运行速度快,因为越过了地址翻译这个步骤
缺点:
1程序要直接加载到内存上,如果程序比物理内存大的话,就无法放上去运行了
2 只运行一个程序过于浪费了
3 无法在不同的操作系统下运行,因为不同的操作系统占用的内存空间大小可能不一样,使得用户程序的起始地址不一样。
多道编程的内存管理:
在多道编程的情况下,无法将程序加到固定的内存地址上,也就无法使用静态地址翻译,必须在程序加载完毕后才能计算物理地址,即运行时地址翻译,动态地址翻译
多道编程的内存管理怎么进行动态地址翻译呢?分为两种,固定分区和非固定分区
固定分区: 将内存分为固定的几个区域,每个区域的大小固定
地址翻译的方法:
物理地址=虚拟地址+程序所在区域的起始地址
两个端值: 基址和极限 ,可以达到地址翻译和保护的目的
动态地址翻译的优点:
1. 程序可以加载到任何地方
2.地址保护
3.使虚拟内存的概念得以实现 ,虚拟内存的根本是将内存扩展到磁盘上,一个虚拟地址仅在被访问了的时候才需要放在内存里,其他时候并不需要占用内存
非固定分区:
找一个空闲的孔:首次适应,最佳适应,最差适应,会有外部碎片,也会有内部碎片,一般是将内存按固定大小进行分配,而不是字节
机制:也是基址和极限寄存器
当程序所占用的空间不够时,将程序倒出来到磁盘上,再加载进内存,这叫做交换(swap)
交换的另一个目的:进程切换,但是一般不这么做,成本高
重叠:一个程序在执行过程中变大了,可以通过交换给它找一个更大的空间来执行,如果程序超过了物理内存,怎么运行?将程序按照功能划分为一段功能相对完整的单元,一个单元执行完后,下一个单元可以将上一个单元覆盖。但是这相当于把内存管理的部分功能交给了用户,是个很恶劣的方法。
双基址:
运行两个一样的程序,只是数据不同,比如同时启动两个PPT,我们希望PPT的程序代码部分能共享。设定两组基址和极限,数据和代码分别共用一组基址和极限,就解决了这个问题。
闲置空间管理:
1. 位图表示法,0表示闲置,1表示已经被占用
2. 链表表示法
解决外部碎片的方法
1.紧缩 compaction
2.分页和分段,允许物理地址空间非连续
分页
地址翻译,对于任意一个虚拟页面,系统知道是否在物理内存中,如果在的话,其对应的物理页面是哪个,不在的话,产生一个系统中断(缺页中断),将虚页从磁盘转到内存,然后将分配给它的物理页面号返回,因此,分页系统的核心是页面的翻译,即从虚拟页面到物理页面的映射,这个翻译有MMU(内存管理单元)完成
MMU怎么做的呢?查页表,对于每个程序,MMU为其保存一个页表,该表里面存放的是虚拟页面到物理页面的映射
页表由硬件直接提供支持,是一个硬件数据结构
TLB(快表):转换表缓冲区,包括页表的一小部分,硬件同时比较,linux是三级页表,但是没有特别慢,因为TLB命中率很高
分页缺点:页表很大,占用了大量内存空间(减小页表尺寸,用多级页表)
优点:页面共享,不会产生外部碎片
多级页表:程序可以分解成页,部分页在内存中,部分在磁盘中,那么页表也可以分为一个个页面,不用的页面放在磁盘中
哈希页表:以虚拟页码作为哈希值,哈希表的每一个条目都是一个链表
反向页表:每个物理地址对应一个虚拟地址 ,所有进程只有一页,页表按物理地址排序,从上到下找
缺页中断:
cpu发出的虚拟地址不在物理内存,就将产生一个缺页中断,处理步骤
1.硬件陷入内核
2.保护通用寄存器
3.操作系统判断所需的虚拟页面号
4.操作系统检查地址的合法性
5.操作系统选择一个物理页面用来存放将要调入的页面(有空闲的,全满的两种情况,没有多余的空间需要选择不同的替换算法将一个页面进行替换)
6.如果选择的物理页面包含有未写磁盘的内容,则首先进行写盘操作
7.操作系统将新的虚拟页面调入内存
8.更新页表
9.发生缺页中断的程序进入就绪状态
10恢复寄存器
11 程序继续
内存抖动:Trashing
每次新的访问都是对一个不在内存的页面进行访问,即每次内存访问都产生一次缺页中断,磁盘访问速度比内存访问速度慢一百万倍,整个系统的效率急剧下降
原因:程序太多,需要降低多道编程的度数,这种做法也叫做负载平衡
比莱迪异常:给一个进程分配的物理页面数增加了,它的缺页中断数一定减少吗?不一定。这种叫做比莱迪异常,可以改变页面替换算法来避免比莱迪异常。
FIFO和clock可能会出现blady异常
虚拟内存:按需分页(demand paging),页面调度算法
页面替换算法
公平算法:
随机算法,先来先出算法(FIFO),第二次机会算法,时钟算法
非公平算法:
最优算法,NRU算法,LRU算法,工作集算法
FIFO: 反例 先加载进来的页面是经常访问的页面
第二次机会算法:
FIFO的基础上增加了一个访问位R,R=1的时候,放到队列最后R=0,直到找到一个R=0的页替换
时钟算法:将页面排成一个时钟的形状
最优算法(optimal):选择一个将来最久不使用的页面进行替换,这个是无法实际实现的算法,可以把这个作为一个标杆,对其他算法进行衡量
NRU算法 (not Recently used):选择一个在最近一段时间内没有被访问过的页面进行替换,根据访问位和修改位进行判断,但是时间分辨粗粒度在最差情况下是一个访问位清零的周期
LRU算法(Least Recently used):NRU的改进
1.用矩阵实现LRU 矩阵k*k维,一开始全为0 第k个虚拟页面被访问时,我们进行如下操作1. 将第k行的值全部设为1,将第k列的值全设置为0
2.使用位移寄存器实现LRU ,在每个规定长度的周期内,将移位寄存器的值往右移动一位,并将对应页面的访问位的值加到该移位寄存器的最左位上
工作集算法:
为页表的每个记录增加一项信息用来记录该页面最后一次被访问的时间,同时设置一个时间值T,如果一个页面的最后一次访问在当前时间减去T之前,则视为在工作集外,否则在工作集内
工作集时钟算法:
用时钟的扫描方法去对工作集算法进行扫描,提高实现效率,这种被大多数商业操作系统所采纳
段式内存管理
分页的缺点?1.页表大(用多级页表克服)2.多级页表慢(用TLB解决)3 页面来回更换(用页面更换算法解决)4.内部碎片(小小的缺憾,微不足道)
还有什么严重的缺点?有,共享困难,虽然理论上按页共享,但是粒度很细,但是不可能实现,因为一页中可能既包括代码又包括数据,一页中只要有一行不能共享的代码,哪怕只有一行,也不能共享。还有一个无法容忍的缺点,同时也是分页系统无法解决的,是一个进程只能占有一个虚拟地址空间
段表一般非常小,分段优点,1.每个逻辑单元可单独占一个虚拟地址空间,使得编写程序的空间大为增长,几乎可以编写出没有尺寸限制的程序 2.由于段是按照逻辑关系而分,共享起来就非常方便。
缺点:外部碎片,一个段必须全部加载到内存,即一个程序必须全部加载到内存,解决的方法(段页式内存管理)
段页式内存管理:
将程序分为多个逻辑段,每个段里面进行分页