存储管理

无存储抽象
使用简单的物理内存:地址从0开始的有限地址集合,每个地址是一个8位的存储单元。
程序执行时,从磁盘放入内存中,进程运行完程序后,将新的程序从自盘装入内存,覆盖上一个程序
要想运行多道程序,需要将当前内存中的所有内容保存到磁盘中,将新程序装入内存再运行即可。
把物理地址暴露给进程,运行多道程序不可避免会造成程序跳转到不正确的地址而崩溃,而且有容易存放操作系统的空间。

地址空间
进程可用于寻址内存的一套地址集合。每个进程拥有自己的地址空间,进程间的地址空间互不干扰。

基址寄存器和界限寄存器
这两个寄存器用来将进程的地址映射到实际的物理地址中,并保证每个进程的地址空间相互独立。基址寄存器存放着程序的起始物理地址,而界限寄存器存放着程序的长度。
进程访问内存时,CPU会用虚拟地址加上基址寄存器的值,然后再从地址总线上寻址物理内存,同时检查程序的地址是否超过了界限寄存器的值。
使用基址寄存器和界限寄存器重定位的缺点是,每次访问内存需要进行加法计算和比较计算,加法计算在没有特殊电路的情况下会很慢。
基址寄存器和界限寄存器

上述方案在进程较少的情况下可行,但现代操作系统的进程很轻易就超过内存容量。
处理内存超载的两种方法,一种是交换技术,另一种是虚拟技术。

交换技术
A和B进程
把进程完整地装入内存,在进程空闲时,存入磁盘,腾出空间给新进程。这个技术的问题在于,无法确定当进程被装入内存时,该分配多大的空间。假设程序的数据段是可增长的,比如它动态的从堆中分配内存,那么进程空间试图增长,如果内存不能增长,而磁盘的交换区也满了,则进程只有挂起。

空闲内存管理
动态分配内存时,需要记录内存的使用情况
1.使用位图的存储管理
将内存分成小到结构字大到几千字节的分配单元。每个分配单元对应位图中的一个位,0表示空闲,1表示被占用。内存的大小和分配单元的大小决定了位图的大小。当一个进程需要k个分配单元时,MMU从内存中寻找k个连续0的串。
2.使用链表的存储管理
维护一个记录已分配内存段和空闲内存段的链表。一个结点的数据段记录进程或空闲区的起始地址和长度。段链表按照地址排序,当一个进程终止时,需要更新链表,将相邻的空闲结点合并成一个空闲结点。

寻找空闲区的算法

首次适配算法:沿地址顺序搜索,直到找到一块足够大的空间。
最佳适配算法:对整个空闲区大小排序,然后搜索整个链表,寻找能够容纳进程的最小空闲区。

为进程和空闲区分别维护一个链表,这样能集中检查空闲区,提高速度。一个能提高性能的做法是,先按照大小对空闲区链表排序,然后使用最佳适配算法或首次适配算法,为进程分配内存。

虚拟内存
解决程序日益增大的问题。
每个程序拥有自己的地址空间,这个虚拟地址空间(VMA)被分割成多个页,每个页地址连续。通过MMU管理虚拟地址空间到物理内存的页映射,运行程序是指将程序引用到的页装载进内存

分页
虚拟地址到物理地址过程
程序给出的虚拟地址首先发送到MMU上,通过查找映射表,然后将真实的物理内存地址发送到总线上。

页表页框映射
叉号表示页面不在内存中。如果程序引用到的页面没有映射,则CPU陷入操作系统,这个陷阱称为缺页中断,操作系统找到一个很少使用的页框,并把内容写入磁盘中,把需要访问的页面读到回收的叶框中,修改映射关系,重新回到中断处执行。

MOV REG,32780

32780这个地址在VMA中32K_36K位置,但是该页面没有映射,引起一个操作系统陷阱。
假设操作系统决定放弃页框1,则它将页表中的虚拟页面1改成叉号,然后将虚拟页面8的叉号改为1,将虚拟页面8写入页框1。
MMU中具体实现如下

注意,输入虚拟地址比输出地址少1位,表明从64K映射到32K。低12位表示页内偏移,直接从MMU输入复制到输出的低12位,高4位为页表的十进制格式的页面号。

页表
页表的目的就是将虚拟页面映射为页框。这个过程会裁剪输入虚拟地址的高位中的某一个位或某些位。在一个分页系统中创建新进程时,操作系统要确定程序和数据初始时多大,在内存中为它们分配页表。并在进程终止时,释放页表。
虚拟地址分为两部分,高位部分为虚拟页号,低位部分为偏移量。例如,对于16位地址和4KB的页面大小,高4位可以指定16个虚拟页面中的一页,而低12位确定了所选页面中的字节偏移量(0~4095)。使用3或5或其他位数拆分虚拟地址也是可行的。不同划分对应不同的页面大小。

页表项
页表项是一个32位的地址(32位操作系统)。
页表项
页框号:映射的目的就是找到这个值。
在/不在位:1是有效,0则表示该表项对应的虚拟页面不在内存中,访问该页面会引起一个缺页中断。
保护位:支出一个页允许什么类型的访问。比如:0->读/写, 1->只读。
修改位:它是用来记录页面使用情况的。在写入一页时有硬件自动设置修改位。如果一个页面被修改过,那么就是“脏”的,则必须把它写回磁盘。反之就是“干净”的,简单地丢弃就可以了。这一位有时也被称为脏位。

页目录、页表、页面三者关系
页目录和页表都是存在线性地址(虚拟地址)里面的。通过页目录中的页表地址找到对应的页表地址,再找到对应的页面地址。对于32位操作系统而言,页表项的大小为4B指的应该是32bit的存储空间。也就是说页表项中数据为4B(4*8=32),页内偏移的大小(12位)决定了页面的大小,也就是是4KB,如果在4GB的虚拟地址空间内,将页面平铺,则有4GB/2KB = 2^20个页表项,因此采用多级分页的策略,一个页目录一般有1024个页表,一个页表一般有1024个页表项。如此一来就有1k*1K*4K = 4GB的空间被映射。

加速分页过程
页表放在内存中,当一条指令将一个寄存器值放入另一个寄存器时,有了分页技术后,操作系统需要先访问内存中的页表,然后再从页表中取对应的内存页

转换检测区(TLB)
它将程序中少量常用的页面放入一个硬件设备中,这个硬件设备通常在MMU中,如果MMU检查到页面地址在TLB中,则直接访问页面对应的物理内存。实际中,TLB的表项数量很少会超过64个。在分页机制下,TLB的加入是为了解决CPU多次访问内存中的页表而引起性能降低的问题。

软件TLB管理
当在TLB表中找不到需要的页面时,将TLB失效问题提交给操作系统。,操作系统更新TLB。
软件处理TLB的速度快于硬件处理TLB的速度。

针对大内存的页表
1、分级页表

32位虚拟地址被分为10位的PT1域,10位的PT2域以及12为的Offset域。PT1域为顶级页表,有1024个项,每个页表项表示4MB的内存空间,一共4GB。PT2域是次级页表项也有1024个项,每一项表示4KB的页大小,一共4MB。

2、倒排页表
倒排页表
实际内存中的一个页框有一个表项,而不是每个虚拟页面有一个表项。MMU不再根据页号来索引物理页框,而直接在搜索RAM的整个页表来查找某个表项。

页面置换算法

页面置换的过程,当程序发生缺页中断时,系统查找时候有空闲页框,如果没有空闲页框,需要将不常用的页面换出内存,如果页面在内存驻留期间被修改过,则重新写入磁盘;否则,用用VMA中的新页覆盖装入内存即可。

1、最优页面置换算法
每个页面被标记首次被访问前所要执行的指令数,每次置换指令数数最大的页面。
缺点是无法实现

2、最近未使用页面置换算法(NRU)
现代操作系统中,每个页面有两个状态位,R状态位标记页面是否被访问过,W状态位标记页面是否被修改过。根据这两个状态位,将页面分为四类,分别是
第0类,没有被访问,没有被修改
第1类,没有被访问,但是被修
第2类,被访问过,没有被修改
第3类,被访问过,也被修改
NRU算法将按类别编号最小的非空类中挑选一个页面被替换。

3、先进先出页面置换算法
在一个时钟滴答中,维护一个当前内存中所有页面的链表,淘汰最早进入内存的页面(表头位置),放到链表的末尾。
缺点是可能会淘汰经常使用的页面

4、第二次机会页面置换算法
在FIFO算法的基础上,淘汰最早进入内存并且没有被访问过的页面。每次检查R位是否为0,如果为0,直接置换掉;如果为1,将其R为清0,放入表尾,变成新装入的页面,继续查找下一个页面。

5、时钟页面置换算法
它为了解决经常在链表中移动结点的问题,将链表变成环形链表,维护一个指针,指向未被访问页面,每次置换后,指针前移一个位置。

6、最近最少使用页面置换算法(LRU)
在缺页中断发生时,置换未使用时间最长的页面
缺点是维护内存中所有页面的链表需要特殊的硬件。

7、最不常用算法(NFU)

8、老化算法

NFU的改进,将每个页面与一个软件计数器关联。红线处出错了,(d)的红线处应改为00010000

9、工作集页面置换算法
请求调页
页面在需要时被调入,而不是预先装入。

局部性访问
进程运行的任何阶段,它都只访问较少的一部分页面。这一部分页也都比较集中。

工作集
一个进程当前正在使用的页面的集合称为工作集。一个进程如果刚开始只装入部分页,会产生很多缺页中断,直到工作集整个装入内存中时,完整装入前的缺页中断会影响程序运行速度,为了避免这个缺陷,分页系统在进程运行前,会将整个工作集装入内存。

颠簸
每执行几条指令就发生缺页中断

预先调页

在程序运行过程中,预先装入推测出的工作集的页面。
常见的推测工作集页面的方法是,确定一个时间间隔T,将过去T时间间隔里内存访问到(即R=1)的页面的集合。
生存时间=当前实际运行时间-上次使用时间

10、工作集时钟页面置换算法

缺点是实现起来开销大

分页系统的设计问题

局部分配策略和全局分配策略
局部分配和全局分配

b)是局部页面置换,它只考虑分配给A的页面,将生存时间最小的页面替换掉
c)是全局页面置换,在A、B、C三个进程集合中选择最小生存时间的页面替换掉。

缺页中断率
每秒的缺页中断数

负载控制
一旦所有进程的组合工作集超过了内存容量,就可能发生颠簸。解决方案是将进程从内存交换到磁盘中。决定交换哪个进程要考虑三个方面的内容
● 进程的类型,是属于计算密集型还是I/O密集型
● 进程的大小
● 分页率

页面大小
页面太大,造成内存碎片太多,浪费空间;页面太小,页表太大,花费在寻道和旋转延迟的时间太长。

分离的指令空间和数据空间

为指令和数据设置分离的地址空间,每个地址空间都是从0开始到最大值。

共享页面
共享内存页
这总情况下, 3、4、6页面时进程P1、P2以及P3共享。程序页总是只读的,因此共享程序也比共享数据页简单些。当共享页面被回收,放入空闲页面池时,所有共享了该页面的所有地址空间的页表都要同步更新。

共享数据的例子
在UNIX系统中,进行fork调用时,会创建父进程的副本,父进程和子进程要共享数据和程序,共享的方法是,将各自进程的页表都指向一个页面集合,而不进行复制页面,只有在其中一个进程对数据页面进程修改时才复制。这种做法称为写时复制。

共享库
当一个程序和共享库链接时,链接器没有加载被调用的函数,而是加载了一小段能够在运行时绑定被调用函数的例程,在库中定义但是没有被调用的函数不会被加载,最终生成的可执行二进制文件也不包含这些未定义外部函数。
如果其他程序已经装载了共享库,就没有必要再次装载它了,并且共享库被装载时,不是一次性的读入内存,而是根据需要,按页装入内存。

解决重定位的问题
如果库被两个进程共享,被不同的进程定位到不同地址上,就不能在装载时重定位了。
解决办法是不要产生使用绝对地址的指令。相反,只能产生使用相对地址的指令。
只使用相对偏移量的代码称为位置无关代码。

内存映射文件
进程发起一个系统调用,将一个文件映射到其虚拟地址空间的一部分。

有关实现虚拟内存系统的几个问题
指令备份
在每条指令执行之前,将程序计数器的内容备份到寄存器中,以防止缺页中断后,系统无法重启引起陷阱的指令。

锁定内存的页面
防止发生I/O通过DMA直接向内存页中传输数据,但是该页却选中被置换的情况。
做法是锁住正在I/O操作的内存中的页面。

磁盘交换区

分段

分段管理
段是一个逻辑实体,程序员必须手动分段,并进行管理。段的长度不定,在运行一段时间后,内存会被分割成空闲区和段区相间,并且这些空闲区都不能使用了。

分段和分页的区别
这里写图片描述

发布了17 篇原创文章 · 获赞 16 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览