内存
逻辑地址=基地址+偏移量
1、地址的转换
将逻辑地址转为物理地址的方法。
1.1、绝对装入
1.2、重定位
重定位要求必须一次性全部装入所有程序,
1.3、动态重定位
需要重定位寄存器支持,该寄存器存放的是该指令执行时的起始地址。那么物理地址=起始地址+逻辑地址
1.4、程序的运行
从写程序到程序运行需要三步:
编译:由编译程序将用户源代码编译成若千个目标模块(编译就是把高级语言翻译为机器语言)。
链接:由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块。
装入(装载):由装入程序将装入模块装入内存运行
上面所描述的三种将逻辑地址转换为物理地址的方法即再装入这一步。而链接成.exe可执行文件的方法也有三种:
明显运行时动态链接方式最灵活,当不调用某模块时边不进行装入。
2、内存管理
(1)内存分配与回收:操作系统负责内存空间的分配与回收
(2)虚拟内存:操作系统需要提供某种技术从逻辑上对内存空间进行扩充
(3)地址转换:操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换(绝对装入、重定位、动态重定位(现代OS最常用的方法))
(4)内存保护:保证各进程在自己的内存空间内运行,不会越界访问。
2.1 内存保护
内存保护有两种方法:
(1)在cpu属于进程的内存空间设置一对上、下限寄存器,里面存放为进程所分配的内存空间的上下限地址,当进程的要访问内存空间时,会与上下限寄存器的地址进行对比,只有当在这个地址范围内,才允许进程访问。
(2)同样利用重定位寄存器存放初始地址与界地址寄存器存放最大逻辑地址(地址长度)。
2.2 内存扩充
2.2.1覆盖技术
当程序大小超过内存大小时,覆盖技术思想:将程序分为很多段( 模块),内存分为一个“固定区”和若干“覆盖区”。常用的段(模块)常驻内存“固定区”中,不常用的段在需要时再调入内存。
例:
对于这样的程序结构,A只能依次调BC模块,不能同时调用
。那么便可以将A放入“固定区”,而BC模块由于不能同时调用,便可以共享一个“覆盖区”,覆盖区大小为最大模块的内存大小,而DEF同样可以共享一个覆盖区。
总结:对于逻辑结构清晰的程序,可以让不能同时被调用的程序段共享覆盖区。只有当其要使用时再调入内存。但是这样的程序结构操作系统是无法了解的,必须有程序员声明。
2.2.2 交换技术
交换(对换)技术的设计思想:内存空间紧张时,系统将内存中某些进程暂时换出外存
,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度)。中级调度策略。
对于挂起的进程的调度,则需要进程控制块PCB常驻内存,以支持后续完成从外存挂起队列后续的调入。
对于交换技术,从外存进行调度时:
1.什么位置保存被换出的进程:具有对换功能的操作系统中,通常把磁盘空间分为文件区
和对换区
两部分。文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区采用连续分配方式。总之,对换区的I/O速度比文件区的更快
。
2.什么时候应该交换:交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。例如:在发现许多进程运行时经常发生缺页
,就说明内存紧张,此时可以换出一些进程;如果缺页率明显下降,就可以暂停换出。
3.换出那些进程:
可优先换出阻塞进程;可换出优先级低的进程;为了防止优先级低的进程在被调入内存后很快又被换出(防止饥饿),有的系统还会考虑进程在内存的驻留时间。
区别:覆盖实在同一程序或进程中,只是把程序分为很多段(模块),而交换涉及进程之间的调度,是在不同进程(作业)之间的。
2.2.3 虚拟内存技术
虚拟内存是基于局部性原理与高速缓存的思想所设计的内存扩充方案。
2.2.3.1 局部性原理
2.2.3.2 虚拟内存概念
2.2.3.3 虚拟内存实现
虚拟内存的实现需要建立在离散分配的内存管理方式基础上。因为采用连续分配,当我第一次调用作业的一部分时,下次调用该作业还得给分配接着上次调用后连续的内存空间。
因此,与传统的非连续分配存储管理不同的是虚拟内存要从内存调入信息和调出信息,因此需要操作系统提供请求调页/段功能和页面/段置换功能。
2.3 内存的分配与回收
2.3.1 连续分配管理
1. 单一连续分配
在单一连续分配方式中,内存被分为系统区和用户区
。系统区通常位于内存的低地址部分,用于存放操作系统相关数据:用户区用于存放用户进程相关数据。内存中只能有一道用户程序,用户程序独占整个用户区空间。
2. 固定分区分配
将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。
实现方式:
3.动态分区分配
动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。
对于动态分配:
1.数据结构记录内存使用情况:
空闲分区表/空闲分区链
。
2.当很多个空闲分区能满足需求时,应该选择那个分区进行分配。—>动态分配算法
3.如何进行分区的分配与回收。
在分配时:
当采用空闲分区表时,只需要在表项中修改分区大小和起始地址即可。
而采用空闲分配链时,只需要将某个节点删掉即可。
在回收时:
如果采用空闲分配表:仍然只是修改分区大小和起始地址即可。当然如果进程结束,分区相邻,那么将分区合并即可。
分区的排序需要依照动态分区分配算法进行确定,不一定按照地址增序。
内部碎片:分配出去但没用上。外部碎片:没分配出去但没法用。由于进程需要一整块连续的内存空间,当碎片不能满足进程的需求时,可以通过紧凑技术来解决外部碎片。而紧凑可以通过交换技术(先将进程调出外存,通过修改重定位寄存器的值重新调入内存)、动态重定位来移动进程,改变进程的起始地址。
4.动态分配算法
4.1首次适应算法
找到大小能满足进程要求的第一个空闲分区
。
4.2 最佳适应算法
按照容量依次递增排列空闲分区,优先使用更小的空闲分区
。即排序后找到大小能满足的第一个空闲分区。
4.3 最坏适应算法
与最佳适应算法相反,按照容量依次递减排列空闲分区,优先使用更大的空闲分区
。仍然时排序后找到大小能满足的第一个空闲分区。这样下去只要第一个分区都不能满足进程的需求,其他后面的分区肯定也不能满足。
4.4 邻近适应算法
是对首次适应算法的改进:在首次适应算法中,每次都要从连头开始查找,这会导致低地址部分出现很多容量很小的空闲分区,而再次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。
实现方法:空闲分区以地址递增的顺序排列(可排成一个循环链表
)。每次分配内存时从上次查戈结束的位置开始查找空闲分区链 (或空闲分区表),找到大小能满足要求的第一个空闲分区。
4.5 算法对比
2.3.2 非连续分配管理
1.基本分页存储管理
将内存空间分为一个个大小相等的分区,成为“页框”,将进程的逻辑地址空间分为和页框大小相等的一个个“页面”。页框和页面都有编号,编号都从0开始,操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,可以放到不相邻的各个页框中。
操作系统会为每一个进程建立一张页表。放在PCB中。页表记录的是页号与内存块号之间的映射关系。
页表的页表项是连续存放的,当内存大小为4G=4×2^30B
,页面大小为4KB=4×2^10B
,则页表项大小至少用3B来表示。而页号为i的页表项可以直接用X(起始地址)+3×i
来计算。
分页存储后,实现逻辑地址到物理地址的转换如下:
1.1基本地址变换机构
基本地址变换机构可以借助进程的页表将逻辑地址转换为物理地址。
首先对页号P进行越界判断,当页表长度≤页号P时即发生越界,产生越界中断(内中断)。
通过起始地址+页号*内存块大小+页内偏移量=物理地址。
1.2 具有快表的地址表换机构
快表
:
快表是一个硬件,当进程切换的时候快表的内容也需要被清除。当进程刚上CPU时,快表是空表,当访问页号为0,页内偏移量为0的逻辑地址时,当越界检查没问题时,由于快表没有数据因此无法命中,还需要先查询内存中的页表(慢表),通过其页号查询出内存块号,然后复制其页表项内容给快表。
而且里面存放的只是最近访问的副本,不是连续存储的,快表里的页号只是针对当前进程,因为进程切换会清空,所以只需对比页号,无需再进行计算。
快表与慢表同时查找更快。
局部性原理
:
1.3 两级页表
对于问题一,当进程很大时,可以分为很多个页,因此当页表项长度一定时,页表长度也会很大,一个页框无法直接保存。因此,可以将页表和进程也一样进行分组,为分好组的离散页表也建立一张页表,成为页表目录(外层页表/顶层页表)。
分好每一个大小相等能放入页框的二级页表后。为其建立页目标表,其内存块号指的是每一个小页表在内存中的块号。
而这样对于32位的逻辑寻址,前十位刚好能表示页目录表的页号0~1023,中十位也能表示分块后小页表的页号(0~1023
)。
因此对于两级页表的地址变换如下:
对于问题2:当需要访问页面是,才把页面调入内存(虚拟存储技术)。在页表内再增加一个标志位来确定其在不在内存中。
当没有TLB时多级页表的访问次数会随着级别的增多而增多。N级页表访问一个逻辑地址需要N+1次访问次数。
2 基本分段存储管理
2.1 分段存储
分页定长,分段不定长,每个段都有段名(用户可以自己定义),都从0开始编制。
内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。
汇编语言:用户所定义的段名最终会被编译程序翻译为对应段号,内存单元会被最终翻译为段内地址。
2.2 段表
段长不定,因此需要显式的存储在段表中,
段号和页号一样可以是隐含的,当物理内存为4G时,每个段表项大小6B(即段号16位+32位物理内存地址空间(基址))。
2.3 地址变换
内存的系统区存放了许多管理软硬件的资源及进程控制块。当进程切换时,进程切换相关的内核程序负责恢复进程运行环境,此时段表寄存器存放了进程的段表始址和段表长度(不是‘段’的长度,是段的个数)。根据段表始址便知道了段表在内存中的位置。查询段表便知道了某一段号的段基址,通过段基址+段内地址=物理地址。
中间要经过两次越界检查,一次是通过逻辑地址的段号与段表长度比较,一次是段内地址与断长比较。
2.4 分段与分页对比
3.段页式管理方式(分段分页相结合)
3.1 段页式管理方式
段页式管理即先按照逻辑模块进行分段,在对每一段进行分页。
分段式管理中,段表存放的是段号、段长和基址,段页式管理中,段表存储的是段号、页表长度(有的段可能用很多页面)和页表存放块号(即页号),而页表存放块号也有对应的页表。
例:段号为0的页表长度为2,页表存放块号为1(页号为1)内存块号为n。
一个进程会对应一个段表,多个页表。
3.2 地址变换
物理地址向逻辑地址的转换,需要3次访存。第一次要访问段表,首先要根据段号判断是否越界中断,根据段表,找到对应的段表项,段表项的存放地址F+S*页表长度。第二次就是根据段表中查出的页表存放块号(页号)在页表中找到对应的内存块号,再根据内存块号+逻辑地址中的页内偏移量=物理地址。最后根据物理地址访问内存单元。
引入快表机构,用段号和页号作为查询快表的关键字,若快表命中则仅需一次访问。
3 虚拟内存详解
请求调页:外存->内存
页面置换:内存->外存
3.1 页表机制-请求分页存储管理机制
请求分页管理相比较基本分页存储管理,其页表多了四项:(状态位:0/1,表示页面是否调入内存;访问字段:表示最近被访问了几次,或者记录上次的访问时间;修改位:0/1,表示页面调入内存后是否被修改过;外存地址:表示页面在外存中的地址。
挡在一个请求分页的系统中,假设此时要访问的页面不在内存中(状态位是0),便会产生一个缺页中断信号,然后操作系统的缺页中断程序会处理这个缺页中断,中断处理的过程中需要IO操作,把页面从外存调入内存。因此,在等待IO操作的过程中,缺页的进程会陷入阻塞,放回就绪队列,只有调页完成后,才会重新唤醒,开始执行。
缺页中断是内中断。
3.1.1 地址变换
请求分页的地址变换,与基本分页不同的是快表的页面一定要是在内存中的即(状态为是1),才能直接命中。而在内存中的页面进行查找时则根据请求分页的规则进行查询。
3.1.2 页面置换算法
3.1.2.1 最佳置换算法(OPT)
OPT从内存往外存调用的是,最长时间内没被访问的页面,或者以后停用的页面,这样可以保证最低的缺页率。
页面置换只会发生在内存块满时。缺页中断是用来调页的,但在前期缺页中断时,由于内存块未满,不一定发页面置换。
3.1.2.2 先进先出置换算法(FIFO)
FIFO每次选择从内存调入外存的页面是最早进入内存的页面。FIFO的实现方式是队列实现的。
3.1.2.3最近最久未使用置换算法(LRU)
LRU从内存往外存调出的是最近最久未使用的页面,通过在每个页面的页表项中,用访问字段记录该页面自上次被访问以来所经历的时间t。
LRU实现困难,开销大,性能是最接近OPT算法的。
3.1.2.4 时钟置换算法(CLOCK/NRU)
CLOCK为每个页面设置一个访问位,将所有页面都通过链接指针链接呈一个循环队列,
页面被访问时,将访问位改为1。而当从内存往外存调出时,检查页的访问位,如果是0,就选择该页换出;如果是1,置换为0,暂不换出。继续扫描。
对于下页面的引用串,刚开始调用页面直至内存块号为满时,那么第一轮扫描访问为肯定都是1,因此第一轮扫描完后,将所有访问位置为0.
那么第二轮开始扫描时,先将一号位(访问位为0)调出并置换为6,访问位改为1,指针停在3号位(访问位为0)。而当3号位重新扫描访问时,因为已经是0,直接将访问位置为1,指针继续扫描,搞好4号位为0.指针停在4号位。
最终7号进入队列时,指针停在2号,2号访问位为0,因此指针停在5号位。
3.1.2.5改进的时钟置换算法
每一次替换指针扫描都会更改访问位,所以会出现访问位为0而修改位为1的情况,修改过指的是调入内存后,页面内容被修改了,没修改过的就没必要写回外存,没有被访问过的,就要替换掉,因为访问过的话,说明内存中有了这页,可以不用管。修改位为主,辅助位为辅。先找没访问的,后找没修改的。
外存内存的数据要一致,因此内存中的页面没有被修改的话便不需要再调出外存。
找不到(0,x)后,和初始的clock一样,在第二轮将访问位置为0。根据这样的优先级其时淘汰的优先等级就是第一轮中的(0,0)(0,1)(1,0)(1,1)。
3.1.2.6 算法对比
3.2 页面分配策略
3.2.1 页面分配、置换策略
驻留集是分页存储管理中分配的物理块的集合,在虚拟存储技术的系统中,驻留集大小小于进程的总大小。
兑换区大小足够时,系统的内存会直接和兑换区进行交互。
兑换空间不够时,不会被修改的数据能直接从文件区调入,换出也不必写回磁盘。会被修改的数据,换出时需写回磁盘兑换区。下次需要时再从对换区调入。
unix方式,将全部数据先放在文件区,因此第一次调用都是从文件去调用,当被使用过后的页面需要换出,则放在对换区,内存直接与对换区进行交互。
3.3内存映射文件
内存映射文件是操作系统向上层程序员提供的系统调用。
当操作系统支持内存映射文件后,程序员对内存的管理便更简单
当使用mmap系统调用时,系统会返回一个指针,该指针指向进程的虚拟地址空间的起始地址,利用该指针可以访问该进程的数据。而采用mmap系统调用后,操作系统只是建立了操作数据和内存之间的映射关系(下图灰色区域),并没有把文件数据进行调用直接读入内存,因此此时处于缺页状态,当要使用内存块为2的文件数据,需要操作系统自动将2号数据读入内存。因此程序员不需要再进行read和write文件数据,由操作系统自动调入数据。
并且文件数据可以需要被很多进程进行调用,但是每个进程的虚拟内存空间是独立的,因此操作系统会进行修改页表,将进程中相同的页面映射到不同的物理页表。来实现不同的进程共享相同的文件数据。