操作系统(11)----内存管理2

简介: 操作系统(11)----内存管理2

操作系统(11)----内存管理1:https://developer.aliyun.com/article/1511161

2.什么时候需要交换?

交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。

例如:在发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程;如果缺页率明显下降,就可以暂停换出。

3.应该换出哪些进程?

①可优先换出阻塞进程;


因为处于就绪态的进程是可以运行的,而处于阻塞态的进程暂时不能运行。


②可换出优先级低的进程;


③为了防止优先级低的进程在被调入内存后很快又被换出,这就有可能导致优先级低的进程饥饿的现象,所以有的系统还会考虑进程在内存的驻留时间。


注:PCB会常驻内存,不会被换出外存。

覆盖技术与交换技术的区别:

1.覆盖技术是在同一个程序或进程中进行的。

2.交换技术是在不同进程(或作业)之间进行的。

3.虚拟存储技术

在传统存储管理方式的基础上引入了交换技术、覆盖技术,使得内存利用率有所提升,并且能从逻辑上扩充内存容量。

但是在传统存储管理中,许多很多暂时用不到的数据也会长期占用内存,导致内存利用率不高。

并且传统存储方案有两个很明显的特征:

一次性:作业必须一次性全部装入内存后才能开始运行。这会造成两个问题:


①作业很大时,不能全部装入内存,导致大作业无法运行;


②当大量作业要求运行时,由于内存无法纳所有作业,因此只有少量作业能运行,导致多道程序并发度下降。


驻留性:一旦作业被装入内存,就会一直驻留在内存中,直至作业运行结束。事实上,在一个时间段内,只需要访问作业的一小部分数据即可正常运行,这就导致了内存中会驻留大量的、暂时用不到的数据,浪费了宝贵的内存资源。


以上传统存储管理方式遇到的问题都可以用虚拟存储技术解决。

首先讲一下局部性原理:

时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)


空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的,并且程序的指令也是顺序地在内存中存放的,由于程序是顺序执行的,所以只要执行了第一条指令,那么与他相邻的第二条指令也有可能在不久之后被接着访问)


•虚拟内存的定义

基于局部性原理,在程序装入时,可以将程序中很快会用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行。就是高速缓存技术,使用频繁的数据放到更高速的存储器中。

在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。


若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。


在操作系统的管理下,在用户看来似乎有一个比实际内存大得多的内存,这就是虚拟内存。这就是操作系统虚拟性的一个体现,实际的物理内存大小没有变,只是在逻辑上进行了扩充。

虚拟内存的特征

多次性:无需在作业运行时一次性全部装入内存,而是允许被分成多次调入内存。

对换性:在作业运行时无需一直常驻内存,而是允许在作业运行过程中,将作业换入、换出。

虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际的容量。

•实现虚拟内存技术的方法

虚拟内存技术,允许一个作业分多次调入内存。如果采用连续分配方式,会不方便实现。因此,虚拟内存的实现需要建立在离散分配的内存管理方式基础上。(非连续分配管理方式下面会讲到,建议先看下面),如图,根据不同的非连续分配存储管理方式形成了不同的实现虚拟内存技术的方法:


传统的非连续分配存储管理的方式与虚拟内存的实现方法最主要的区别在于:


对于虚拟内存,需要满足更高的需求,就是:


1.在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。


2.若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。


由于这两个需求的增加,操作系统需要在基本的非连续分配存储管理中加入请求调页(或请求调段)功能,页面置换(或段置换)功能


请求调页(或请求调段)功能:若需要的页(段)不在内存中,操作系统需要将其调入内存。


页面置换(或段置换)功能:当内存空间不足时,操作系统需要将暂时用不到的分页(分段)暂时调出内存。


3.当页面被访问时,需要修改请求页表(请求分页存储管理中对应的页表)中新增的页表项

(1)请求分页管理技术

之前讲过请求分页存储管理与基本分页存储管理的主要区别在于,请求分页存储管理多了请求调页功能与页面置换功能。

请求分页存储管理与基本分页存储管理的页表机制有何不同?

与基本分页管理相比,请求分页管理中,为了实现“请求调页”,操作系统需要知道每个页面是否已经调入内存;如果还没调入,那么也需要知道该页面在外存中存放的位置。


操作系统需要通过某些指标来决定到当内存空间不够时,要实现“页面置换”时,到底换出哪个页面;有的页面没有被修改过,就不用再浪费时间写回外存。有的页面修改过,就需要将外存中的旧数据覆盖,因此,操作系统也需要记录各个页面是否被修改的信息。


相比于基本分页存储管理中的页表:

请求分页存储管理的页表如下所示,称为请求页表

状态位表示是否已调入内存:例如0号页状态位为0,表示0号页没有调入内存。这里也称有效位


访问字段可记录最近被访问过几次,或记录上次访问的时间,供置换算法选择换出页面时参考。(例如换出访问次数少的或者是很长时间没有访问的页面)


修改位表示页面调入内存后是否被修改过,没有修改过的页面是不需要写回外存的,这里也称脏位,和Cache中的脏位功能一致


外存地址表示各个页面在外存中的存放位置


如下图所示,调入主存的页面在主存中,没有调入主存的页面在磁盘中:

为了实现请求调页功能,系统中引入了缺页中断机构

假设此时要访问逻辑地址=(页号,页内偏移量)=(0,1024)


缺页中断机构会根据页表项判断该页面是否在内存当中,若没有在内存中,即状态位为0,那么会产生缺页中断。然后由操作系统的缺页中断处理程序处理中断。中断处理的过程需要I/O操作,把页面从外存调入内存。


所以在等待I/O操作的这一过程中,之前发生缺页的这一进程会阻塞,放入阻塞队列中,调页完成后再将其唤醒,放回就绪队列中。


如果内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中相应的页表项。


例如,此时有空闲的块a在内存中,就可以把空闲块分配给缺页的进程,并且将所缺的页面装入该块中,并且修改页表项中对应的数据。

如果内存中没有空闲块,则由页面置换算法选择一个页面淘汰,若该页面在内存期间被修改过,则要将其写回外存。未修改过的页面不用写回外存。


例如,这里换页面2,那么由于2号页面被修改过,就需要写回外存,并且覆盖外存中原来的数据。那么2号页面以前占用的c号块,就可以让出来,给0号页使用了。

修改页表项中对应的数据,最终得:

缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,因此属于内中断,由于此中断是能够被修复的,所以属于内中断中的故障。

另外补充一下:

一条指令在执行期间,可能产生多次缺页中断。(如:copy A to B,即将逻辑地址A中的数据复制到逻辑地址B,而A、B属于不同的页面,则有可能产生两次中断)

总结:引入了缺页中断机构后,系统才能实现请求调页的功能。

地址变换机构:

① 首先将页号与页表长度进行对比,检查此时页号是否越界


② 若没有越界,则查询快表中有没有这一页表项,快表命中,可直接得到最终的物理地址,若快表没有命中,则需要查询请求页表,找到对应页表项后,若对应页面未调入内存,即状态位为0。则产生缺页中断,之后由操作系统的缺页中断处理程序进行处理(包括调页和页面置换以及修改对应页表项)。


③ 调入的页面对应的表项会直接加入快表,查询快表,此时命中,则直接得到目标物理地址


注:快表中有的页面一定是在内存中的。若某个页面被换出外存,则快表中的相应表项也要删除否则可能访问错误的页面。

具体步骤如下:

对于上图:

① 只有“写指令”才需要修改“修改位”。并且,一般来说只需修改快表中的数据,只有要将快表项删除时才需要写回内存中的慢表。这样可以减少访存次数。


② 和普通的中断处理一样,缺页中断处理依然需要保留CPU现场。


③ 需要用某种“页面置换算法”来决定一个换出页面。


④ 换入/换出页面都需要启动慢速的I/O操作,可见,如果换入/换出太频繁,会有很大的开销。


⑤页面调入内存后,需要修改慢表,同时也需要将表项复制到快表中。


在具有快表机构的请求分页系统中,访问一个逻辑地址时,若发生缺页,则地址变换步骤是:查快表(未命中)--查慢表(发现未调入内存)--调页(调入的页面对应的表项会直接加入快表)--查快表(命中)--访问目标内存单元


这里需要查两次快表,第一次未命中,将调入的页面对应的表项加入快表,再次查询快表,就可以直接访问目标内存单元。

这里的地址变换与基本分页的区别:

①找到页表项时需要检查页面是否在内存中

②若页面不在内存中,需要请求调页

③若发现内存中没有空闲空间,那么需要通过页面置换算法进行页面置换

④页面调入内存后,需要修改相应的页表项

(2)页面置换算法

页面的换入、换出需要磁盘I/O,会有较大的开销,因此好的页面置换算法应该追求更少的缺页率,也就是减少换入换出内存的次数。

•最佳置换算法

每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。


例:假设系统为某进程分配了三个内存块,并考虑到有一下页面号引用串(会依次访问这些页面):7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1


在访问第一个2时,由于此时内存块已满,选择从 0,1,7 中淘汰一页。按最佳置换的规则往后寻找,最后一个出现的页号就是要淘汰的页面,所以最后一个出现的页号为7,所以淘汰7号页面。访问其他页面同理。

接下来访问0号页面,由于0号页面已经在内存中了,所以不需要将页面换出内存。

整个访问过程中,缺页中断发生了9次,即产生了页面的换入和换出。


但是页面置换只发生了6次,在前3个访问页面的过程中,虽然发生了页面调入内存,但是并没有产生页面置换。只有内存块满才会发生页面置换


所以缺页时未必发生页面置换。若还有可用的空闲内存块,就不用进行页面置换。


将缺页中断次数/访问页面次数即可得到缺页率:


9/20=45%

最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预判页面访问序列。因此,最佳置换算法是无法实现的。

•先进先出置换算法

每次选择淘汰的页面是最早进入内存的页面。

所以把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可。


队列的最大长度取决于系统为进程分配了多少个内存块。


例:假设系统为某进程分配了三个内存块,并考虑到有以下页面号引用串:

3,2,1,0,3,2,4,3,2,1,0,4


首先访问3,2,1队列,并且将页面依次放入队列的队尾

接下来访问0号页面,根据系统中的队列,我们知道3号页面进入内存最早,所以淘汰3号页面,将0号页面放入相应内存块,并且将0号页面放入队尾。访问其他页面同理。

可以观察到,缺页次数为9次

若为进程分配4个内存块,则得到:

分配四个内存块时,缺页次数:10次。分配三个内存块时缺页次数:9次。但是为进程分配的内存块越多,缺页次数应该越少才对,对于这一异常称为:


Belady 异常----当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。

只有 FIFO 算法会产生 Belady 异常。另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,算法性能差。

•最近最久未使用置换算法

每次淘汰的页面是最近最久未使用的页面。

实现方法:赋予每个页面对应的页表项中,用访问字段记录该页面自上次被访问以来所经历的时间t。当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面。

例:假设系统为某进程分配了四个内存块,并考虑到有以下页面号引用串:1,8,1,7,8,2,7,2,1,8,3,8,2,1, 3,1,7,1,3,7


在访问以下图中的3号页面时,由于内存块已满,必须选择淘汰一个页面。


在手动做题时,若需要淘汰页面,可以逆向检查此时在内存中的几个页面号。在逆向扫描过程中最后一个出现的页号就是要淘汰的页面。例如下图,此时在内存中拥有1,8,7,2页面,出现的顺序依次为8,1,2,所以7号页面是最近最久未被访问的页面。


因此淘汰7号页面。3号页就会放入到7号页以前存在的内存块3中。其他页面访问同理。

该算法的实现需要专门的硬件支持,虽然算法性能好,但是实现困难,开销大

•时钟置换算法

最佳置换算法性能最好,但无法实现;


先进先出置换算法实现简单,但算法性能差;


最近最久未使用置换算法性能好,是最接近OPT算法性能的,但是实现起来需要专门的硬件支持,算法开销大。


时钟置换算法是一种性能和开销较均衡的算法,又称CLOCK算法,或最近未用算法(NRU,Not Recently Used)


简单的CLOCK 算法实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需检査页的访问位。如果是0,就选择该页换出;如果是1,则将它置为0,暂不换出,继续检查下一个页面,若第一轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描 (第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)

例:假设系统为某进程分配了五个内存块,并考虑到有以下页面号引用串:1,3,4, 2,5,6, 3,4,7

由于内存块为5个,所以1,3,4,2,5这5个页面会通过链接指针的方式,形成循环队列:

接下来会访问6号页面,但是由于内存块满,所以开始从循环队列的队首开始扫描,尝试找到访问位为0的页面,并且被扫描的页面需要将访问位由1改为0,所以第一轮扫描后,所有的位由1变为0

进行第二轮访问时,由于1号页面访问位为0,则淘汰1号页面,所以:

①6号页面替换1号页面

②6号页访问位置为1

③指针指向下一个页面,其他页面同理。

接下来访问3,4号页,将其访问为从0变为1

接下来访问7号页,由于7号页没有在内存中,所以从当前指针位置开始依次扫描,找到第一个访问位为0的页面,并且扫描过的页面需要由1变为0。


所以3号和4号页面扫描后,访问位由1变为0。


扫描到2号页面时,由于2号页面访问位为0,所以2号页面被淘汰,将7号页面放入此内存块中,并且将其访问位置为1,指针指向下个页面。

操作系统(11)----内存管理3:https://developer.aliyun.com/article/1511165

目录
相关文章
|
2月前
|
存储 Linux 调度
深入理解操作系统:从进程管理到内存分配
【8月更文挑战第44天】本文将带你深入操作系统的核心,探索其背后的原理和机制。我们将从进程管理开始,理解如何创建、调度和管理进程。然后,我们将探讨内存分配,了解操作系统如何管理计算机的内存资源。最后,我们将通过一些代码示例,展示这些概念是如何在实际操作系统中实现的。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
|
3月前
|
安全 索引
操作系统中的内存管理策略
【8月更文挑战第23天】
84 1
|
1月前
|
分布式计算 算法 大数据
探索操作系统的核心:调度与内存管理机制
【10月更文挑战第11天】 本文深入探讨了操作系统中两大核心功能——调度与内存管理机制。通过分析调度算法、进程状态转换及内存分配策略等关键方面,揭示了它们如何共同维护系统性能和稳定性。旨在为读者提供对操作系统内部运作的深刻理解,同时引起对优化策略的思考。
59 5
|
1月前
|
算法
深入理解操作系统:内存管理机制的探索之旅
【10月更文挑战第2天】在数字世界的浩瀚海洋中,操作系统犹如一艘精密的航船,承载着软件与硬件的和谐共舞。本文将揭开内存管理的神秘面纱,从基础概念到高级策略,引领读者领略操作系统内存分配的智慧。通过深入浅出的解释和生动的比喻,我们一同遨游在内存的江河之中,感受操作系统如何巧妙地协调资源,确保数据的有序流动。让我们跟随内存的脚步,探索那些隐藏在每次点击、每次命令背后的奥秘。
|
1月前
|
监控 开发者
深入理解操作系统:内存管理的艺术
【10月更文挑战第2天】在数字世界的幕后,操作系统扮演着至关重要的角色。本文将深入探索操作系统的心脏——内存管理,揭示它是如何协调和管理计算机的宝贵资源。通过浅显易懂的语言和生活化的比喻,我们将一起走进内存管理的奥秘世界,了解它的原理、机制以及为何对整个系统的性能和稳定性有着不可替代的影响。无论你是技术新手还是资深开发者,这篇文章都将为你打开新的视角,让你对日常使用的设备有更深层次的认识和尊重。
|
1月前
|
缓存 算法 调度
深入浅出操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅。我们将从进程管理的基本概念出发,逐步深入到内存管理的复杂世界,最终探索如何通过实践技巧来优化系统性能。文章将结合理论与实践,通过代码示例,帮助读者更好地理解操作系统的核心机制及其在日常技术工作中的重要性。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往操作系统深层次理解的大门。
|
1月前
|
存储 算法 C语言
MacOS环境-手写操作系统-17-内存管理算法实现
MacOS环境-手写操作系统-17-内存管理算法实现
36 0
|
1月前
|
Java C语言 iOS开发
MacOS环境-手写操作系统-16-内存管理 解析内存状态
MacOS环境-手写操作系统-16-内存管理 解析内存状态
35 0
|
1月前
|
存储 算法 C语言
MacOS环境-手写操作系统-15-内核管理 检测可用内存
MacOS环境-手写操作系统-15-内核管理 检测可用内存
35 0
|
2月前
|
Python
python对电脑的操作,获取几核,获取操作系统,获取内存
python对电脑的操作,获取几核,获取操作系统,获取内存