内存分成两部分:内核使用部分、用户使用部分,那么它们是否是平等的呢?
不平等,试想如果是平等的:那么我们可以随意修改内核所用的内存,那么系统岂不是乱套啦!
既然不平等,就要引入保护机制,防止恶意修改。
我们如何记录哪些内存已经分配/未分配呢?这些信息保存在哪里?
有以下几种物理内存分配方案:
CPU(程序执行处),内存(放置了代码和处理的数据),设备(I/O)
(1)抽象,逻辑地址空间;
(2)保护,独立地址空间;
(3)共享,访问相同内存;
(4)虚拟化,更多的地址空间,对应用程序透明
物理地址空间:硬件支持的地址空间
逻辑地址空间:一个运行的程序所看到的内存空间
两者之间存在映射关系,最终执行时还是落在物理地址空间上。
源程序不能再计算机上直接被运行,需要通过三个阶段的处理:编译程序处理源程序并生成目标代码,链接程序把他们链接为一个可重定位代码,此时该程序处于逻辑地址空间中;下一步装载程序将可执行代码装入物理地址空间,直到此时程序才能运行。
可执行程序逻辑地址转换为物理地址的过程被称为 “地址重定位”。
逻辑地址是如何映射到物理地址:
CPU方面
1.运算器ALU需要在逻辑地址的内存内容(CPU要逻辑地址)
2.内存管理单元MMU寻找在逻辑地址和物理地址之间的映射(然后MMU找逻辑和物理地址的关系)
3.控制器从总线发送在物理地址的内存内容的请求(关系找到后,去找对应物理地址)
内存方面
4.内存发送物理地址内存内容给CPU(物理地址找到了,给CPU)
操作系统方面
5.建立逻辑地址和物理地址之间的映射(确保程序不相互干扰)
内存碎片:两个进程之间连续物理内存地址空间未使用的内存为内存碎片
外部碎片:在分配单元之间的未使用内存
内部碎片:在分配单元内部未使用的内存
连续内存分配有两种实现方式:固定分区分配,动态分区分配
动态分区分配
最先匹配(地址优先):从0地址往后查找和使用第一个可用空闲快
最佳匹配(空闲分区大小优先):找比需求大但最接近需求的空闲内存块,产生尽可能小的内存碎片。
最差匹配(最大空闲分区优先):使用最大的空闲块。
碎片整理:通过调整进程占用的分区位置来减少或避免分区碎片。
使用条件:所有的应用程序可以动态重定向。
调整内存中程序运行的位置,通过拷贝尽量把程序放到一起,空出较多的空闲位置。
外存(swap分区)当做内存的备份,把在等待的进程包括数据放在外存上,腾出空间给其余运行的进程(抢占等待进程,回收其内存),这个方法也要考虑开销和换哪个进程。
把逻辑地址空间分散到多个物理地址空间,堆→堆,运行栈→运行栈,程序数据→数据,运行exe→代码和库
逻辑地址空间是连续的,物理地址是离散的,每个段的逻辑地址都由段号s和段内偏移addr构成。
段内要求连续,段间不一定连续,故整个进程的地址空间是二维的。
首先用段号查段表,里面有它的起始地址和长度,由操作系统控制。
MMU检查addr偏移是否大于段的长度,合法就用段基址+偏移得到实际的物理地址
分页也是实现机制和寻址,也需要页号和偏移,区别在于页帧的size不变。
快表(TLB):通过缓存技术解决内存访问性能问题,缓存近期访问的页表项,使用关联存储实现,具备快速访问。快表命中率可达90%
多级页表:通过间接访问技术解决内存访问性能问题,后一级页表大小对应前一级需要存储的地址大小,形成树状结构,由于进程不会使用到所有的页表,故可以减小页表大小.增加了内存访问次数和开销,但是节省了保存页表的空间。
反置页表:大地址空间,多级页表很繁琐。
段式存储在内存保护方面有优势,页式存储在内存利用和优化转移到后备存储方面有优势。结合段式存储和页式存储。
通过指向相同的页表基址,可实现进程间的段共享。
虚拟存储是在非连续存储基础上把一部分数据放在外存里边。可以得到更大的内存存储空间,且保持可观的访问速度。
目标:在较小的可用内存中运行较大的程序。常用于多道程序系统,与分区存储管理配合使用。
原理:按自身逻辑把程序分成几个功能上相对独立的模块,不会同时执行的模块可以共享同一块内存区域,按时间先后运行(分时)。
缺点:
(1) 设计开销,程序员要划分模块和确定覆盖关系,编程复杂度增加了
(2) 覆盖模块从外存装入内存,实际是以时间来换空间。
目标:多道程序在内存中时,让正在运行的程序或需要运行的程序有更多的内存资源。
方法:可将暂时不能运行的程序送到外存以获得空闲内存空间,操作系统在内存管理单元MMU帮助下把一个进程的整个地址空间的内容保存到外存中(换出swap out),而将外存中的某个进程的地址空间读入到内存中(换入swap in)。其大小为整个程序的地址空间(比较大,几十几百个页)。
交换技术实现中的几个问题
覆盖只能发生在那些(程序内)相互之间没有调用关系的程序模块之间,因此程序员必须给出程序内的各个模块之间的逻辑覆盖结构。
交换技术是以在内存中进程为单位来进行的,它不需要程序员给出各个模块之间的逻辑覆盖结构。
交换发生在内存中进程与管理程序或操作系统之间,而覆盖则发生在运行程序的内部模块之间。
局部性原理是根据程序的特点分析出的几条特征,比如一个数据的两次访问很可能集中在比较短的时间内,当前访问的数据邻近的数据很可能马上也会被邻近的指令访问。
局部性原理:程序在执行过程中的一个较短时期,所执行的指令地址和指令的操作数地址,分别局限于一定区域。
思路:将不常用的部分内存块暂存到外存。
原理:
实现方式:
虚拟存储的基本特征
思路:
页表项增加了:驻留位,修改位,保护位,访问位
逻辑地址查找页表对应的页表项不存在,需要在外存中寻找页面并修改页表项。若页表项驻留位为0,则产生缺页异常,执行缺页异常服务程序
置换算法的功能:当出现缺页时,需要调入新页面但是内存已满时,置换算法用于选择被置换的物理页面(从内存中拿走一个,从外存中拿进来一个);
目标:尽可能减少页面的换入换出次数。把未来不再使用的或短期内较少使用的页面换出,通常只能在局部性原理的指导下依据过去的统计数据来进行预测。
页面锁定(frame locking):用于描述必须常驻内存的操作系统的关键部分或时间关键(time-critical)的应用进程。实现方法是,在页表中添加锁定标志位(lock bit)。
置换算法可以分为两类:局部页面置换算法和全局页面置换算法。
局部页面置换算法:置换页面的选择范围仅限于当前进程占用的页面内。
具体实现:最优算法,先进先出算法、最近最久未使用算法、时钟算法,最不常用算法。
全局页面置换算法:置换页面的选择范围是所有可换出的物理页面(可以置换其他进程的页面)
具体实现:工作集算法、缺页率算法
举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
开始运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。
例题:物理页帧数量为3,虚拟页访问序列为 0,1,2,0,1,3,0,3,1,0,3,请问采用最优置换算法的缺页次数为(4)
插入顺序 | 0 | 1 | 2 | 0 | 1 | 3 | 0 | 3 | 1 | 0 | 3 |
---|---|---|---|---|---|---|---|---|---|---|---|
内存 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
内存 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | |
内存 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | ||
是否缺页 | 是 | 是 | 是 | 是 |
选择在内存驻留时间最长的页面进行置换
实现:维护一个记录所有内存中的逻辑页面链表
链表元素按驻留内存的时间排序,链首最长,链尾最短,出现断页时,选择链首页进行置换,新页面加到链尾
特征:
i. 性能较差,实现简单,调出的页面可能是经常访问的
ii. 进程分配物理页面数增加时,缺页并不一定减少
iii. 很少单独使用。
例题:物理页帧数量为3,虚拟页访问序列为 0,1,2,0,1,3,0,3,1,0,3,请问采用LRU置换算法的缺页次数为(6)
插入顺序 | 0 | 1 | 2 | 0 | 1 | 3 | 0 | 3 | 1 | 0 | 3 |
---|---|---|---|---|---|---|---|---|---|---|---|
内存 | 0 | 0 | 0 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 |
内存 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | |
内存 | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 1 | ||
是否缺页 | 是 | 是 | 是 | 是 | 是 | 是 |
选择最长时间没有被引用的页面进行置换,如果某些页面长时间未被访问,则它们在将来还可能长时间不会访问。
实现:为了实现 LRU,需要在内存中维护一个所有页面的链表或者栈。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。
特征:最优置换算法的一种近似,每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。
4,7,0,7,1,0,1,2,1,2,6
放6的时候将4置换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qqHMl47Z-1592879546095)(https://camo.githubusercontent.com/88a3ea6558a8b9326f6fd95d74b2ff07625427b5/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f65623835393232382d633066322d346263652d393130642d6439663736393239333532622e706e67)]
例题:物理页帧数量为3,虚拟页访问序列为 0,1,2,0,1,3,0,3,1,0,3,请问采用LRU置换算法的缺页次数为(4)
插入顺序 | 0 | 1 | 2 | 0 | 1 | 3 | 0 | 3 | 1 | 0 | 3 |
---|---|---|---|---|---|---|---|---|---|---|---|
内存 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
内存 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | |
内存 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | ||
是否缺页 | 是 | 是 | 是 | 是 |
仅对页面的访问情况进行大致统计,是LRU和FIFO的折中。
数据结构
i. 在页表中增加访问位,描述页面在过去一段时间的内存访问情况
ii. 各页组织成环形链表,指针指向最先调入的页面
算法
为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需检查页的访问位。如果是0,就选择该页换出;如果是1,则将它置为0,暂不换出,继续检查下一个页面,若第- - ~轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择–个淘汰页面最多会经过两轮扫描)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jgTcEqKZ-1592879546097)(https://camo.githubusercontent.com/be6880af7be4c35175b739114a78d6bf151c740f/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f35663565663062362d393865612d343937632d613030372d6636633535323838656162312e706e67)]
CLOCK算法的性能比较接近LRU,而通过增加使用的位数目,可以使得CLOCK算法更加高效。在使用位的基础上再增加一个修改位,则得到改进型的CLOCK置换算法。这样,每一帧都处于以下四种情况之一:
最近未被访问,也未被修改(u=0, m=0)。
最近被访问,但未被修改(u=1, m=0)。
最近未被访问,但被修改(u=0, m=1)。
最近被访问,被修改(u=1, m=1)。
算法执行如下操作步骤:
从指针的当前位置开始,扫描帧缓冲区。在这次扫描过程中,对使用位不做任何修改。选择遇到的第一个帧(u=0, m=0)用于替换。
如果第1)步失败,则重新扫描,查找(u=0, m=1)的帧。选择遇到的第一个这样的帧用于替换。在这个扫描过程中,对每个跳过的帧,把它的使用位设置成0。
如果第2)步失败,指针将回到它的最初位置,并且集合中所有帧的使用位均为0。重复第1步,并且如果有必要,重复第2步。这样将可以找到供替换的帧。
实现:
i. 每个页面设置一个访问计数
ii. 访问页面时,访问计算加1
iii. 缺页时置换计算最小的页面
特征:
i. 算法开销大
ii. 开始频繁使用,但以后不使用的页面很难置换(计数后期右移)
LRU与LFU的区别:
i. LRU关注多久未访问,时间越短越好 维护一个栈
ii. LFU关注访问次数,次数越多越好
当给一个进程增加页帧数分配时,在FIFO替换算法策略下可能会出现缺页率增加的异常现象。
以栈结构的算法无Belady
思路:全局置换算法为进程分配可变数目的物理页面。
要解决的问题:
工作集:一个进程当前正在使用的逻辑页面集合,可表示为二元函数W(t, delta)
常驻集:在当前时刻,进程实际驻留内存当中的页面集合。
a) 工作集与常驻集的关系:工作集是进程在运行过程中固有的性质。常驻集取决于系统分配给进程的物理页面数目和页面置换算法。
b) 缺页率与常驻集的关系:常驻集包含工作集时,缺页较少;工作集发生剧烈变动时,缺页较多;进程常驻集大小达到一定数目后,缺页率也不会明显下降。
换出不在工作集中的页面
实现:
i. 维护一个窗口大小delta,表示当前时刻前delta个内存访问的页引用是工作集
ii. 访存链表:维护窗口内的访存页面链表
iii. 访存时,换出不在工作集的页面;更新访存链表
iv. 缺页时,换入页面;更新访存链表
a) 缺页率:缺页次数/内存访问次数 或 缺页平均时间间隔的倒数
b) 算法:通过调节常驻集大小,使每个进程的缺页率保持在一个合理的范围内。
c) 实现:访存时,设置引用位标志;缺页时计算从上次缺页时间Tlast到现在Tcurrent的时间间隔。
a) 抖动
i. 进程物理页面太少,不能包含工作集合
ii. 造成大量缺页,频繁置换
iii. 进程运行速度变慢
b) 抖动的原因
随着进程驻留内存的进程数目增加,分配给每个进程的物理页面不断减少,缺页率不断上升。
操作系统需在并发水平和缺页率之间达到一个平衡:选择一个适当的进程数目和进程需要的物理页面数。
c) 负载控制:通过调节并发进程数MPL来进行系统负载控制