操作系统面试
操作系统
一. 什么是操作系统
- 操作系统(Operating System,简称 OS)是管理计算机硬件与软件资源的程序,是计算机的基石。
- 操作系统本质上是一个运行在计算机上的软件程序 ,用于管理计算机硬件和软件资源。 举例:运行在你电脑上的所有应用程序都通过操作系统来调用系统内存以及磁盘等等硬件。
- 操作系统存在屏蔽了硬件层的复杂性。 操作系统就像是硬件使用的负责人,统筹着各种相关事项。
- 操作系统的内核(Kernel)是操作系统的核心部分,它负责系统的内存管理,硬件设备的管理,文件系统的管理以及应用程序的管理。 内核是连接应用程序和硬件的桥梁,决定着系统的性能和稳定性。
二. 谈一下操作系统的系统调用
首先得说一说用户态和内核态
1. 用户态和内核态的区别
由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 :用户态 和 内核态
- 用户态(user mode) : 受限的访问内存,用户态运行的进程可以直接读取用户程序的数据,但不允许访问外围设备。
- 内核态(kernel mode):可以简单的理解系统态运行的进程或程序几乎可以访问计算机的任何资源,不受限制。可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. 也可以将自己从一个程序切换到另一个程序
2. 系统调用
2.1 系统调用的基本概念
- 我们运行的程序基本都是运行在用户态, 但是有时候程序确实需要做一些内核态的事情, 使用内核态级别的资源有关的操作(如文件管理、进程控制、内存管理等),都必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。
- 系统调用是用户态进程主动要求切换到内核态的一种方式,让用户在编程时可以调用的操作系统功能,系统调用是操作系统提供给编程人员的唯一接口
- 例如从硬盘读取数据, 或者从键盘获取输入等,而唯一可以做这些事情的就是操作系统, 所以此时程序就需要先操作系统请求以程序的名义来执行这些操作(比如java的I/O操作底层都是通过native方法来调用操作系统)。
2.2 系统调用的功能分类
- 设备管理。完成设备的请求或释放,以及设备启动等功能。
- 文件管理。完成文件的读、写、创建及删除等功能。
- 进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。
- 进程通信。完成进程之间的消息传递或信号传递等功能。
- 内存管理。完成内存的分配、回收以及获取作业占用内存区大小及地址等功能。
2.3 用户态转换为内核态的三种方式
-
系统调用
- 这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使 用操作系统提供的服务程序完成工作,比如print()实际上就是执行了一个输出的系统调用,fork()就是执行了一个创建新进程的系统调用。
- 而系统调用的机制其核心还是使用了操作系统为用户 特别开放的一个中断来实现,例如Linux的int 80h中断。
-
异常
- 当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
-
**外围设备的中断 **
- 当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条指令(用户态)转而执行与该中断信号对应的中断处理程序(内核态)
- eg:如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到 内核态的切换。比如完成硬盘读写操作请求后,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
三. 进程和线程的区别(见java并发面试)
四. 进程的生命状态
和线程类似(见java并发面试)
1. 进程生命状态的基本概念
- 创建状态(new) :进程正在被创建,尚未进入就绪队列,到就绪状态的状态。
- 就绪状态(ready) :进程已处于准备运行状态,即进程获得了除了处理器之外的一切所需资源,一旦得到处理器资源(处理器分配的时间片)即可运行,可能会有多个进程处于就绪状态,排成就绪队列。
- 运行状态(running) :当进程已获得处理机,进程正在处理器上上运行
- (单核 CPU 下任意时刻只有一个进程处于运行状态,单处理机系统中只能有一个进程处于执行状态,多处理机系统中可能有多个进程处于执行状态)
- 阻塞状态(waiting) :又称为等待状态,进程正在等待某一事件而暂停运行,如等待某资源为可用、进程等待I/O的完成、等待缓冲空间等。即使处理器空闲,该进程也不能运行。
- 结束状态(terminated) :一个进程已正常结束或非正常结束,操作系统已将它从就绪队列中移出,还未将它撤销时的状态。
2. 进程状态之间的切换
-
进程在执行期间可以多次处于就绪状态和执行状态,也可多次处于阻塞状态,但处于新状态只有一次。
(1)新状态->就绪状态:当就绪队列允许接纳新进程时,系统便把处于新状态的进程移入就绪队列。
(2)就绪态->运行状态:进程调度程序为处于就绪状态的进程分配处理机后,该进程进入运行状态。
(3)运行态->阻塞状态:正在执行的进程因需要等待某事件而无法执行。
(4)阻塞状态->就绪态:进程所等待的事件发生了,进程就从阻塞状态进入就绪状态。
(5)运行态->就绪状态:正在执行的进程因时间片用完而被暂停执行;或者在可抢占调度方式中,一个优先权高的进程到来后,正在执行的低优先权的进程被强制撤下处理机,转换为就绪状态。
(6)运行态->终止状态:一个进程已完成或发生某种特殊事件,进程将变为终止状态。
五. 进程间的通信方式
1.管道
1.1 匿名管道
-
管道/匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
-
匿名管道的通信步骤
(1)父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端;
-
int pipe(int filed[2]);
函数功能:调用pipe函数时在内核中开辟出一块缓冲区(称为管道)用于通信,参数为输出型参数,返回值为传出的两个文件描述符,其中filed[0]指向管道的读端,filed[1]指向管道的写端(其中0相当于标准输入,1相当于标准输出),所以管道在用户程序看起来就像一个打开的文件。调用成功返回0,调用失败返回-1
(2)父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道;
(3)父子进程根据相应的需求关闭掉对应的读端或者写端;
-
如图所示
-
1.2 命名管道
匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。
-
命名/有名管道(Names Pipes) :
-
有名管道以磁盘文件的方式存在,可以实现本机任意两个不相关进程通信。
-
有名管道严格遵循先进先出(first in first out)。
-
它也是半双工通信,只能允许单向通信
-
1.3 匿名管道和命名管道的区别:
- 匿名管道是由pipe函数创建 并打开的
命名管道是由mkfifo函数创建 的 ,打开用open - 匿名管道只能用于有亲缘关系的进程间通信,命名管道可以实现任意两个不相关进程的通信
2. 信号
- 信号(Signal) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
3. 消息队列
消息队列(Message Queuing) :是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
- 特点:
- 管道和消息队列的通信数据都是先进先出的原则。
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
- 因为与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是:消息队列存放在内核中,只有在内核重启(即操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。
- 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取,比 FIFO 更有优势。
- 消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺陷。
4.共享内存
4.1 信号量
-
信号量(Semaphores) :信号量是一个计数器,信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。这种通信方式可以避免多个进程对共享区域数据访问的竞争(互斥),也可以实现多个进程对共享区域数据的同步访问
-
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
-
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
-
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
-
#什么是PV操作? #PV操作的操作对象是信号量。信号量的初值应该大于等于0 sem > 0 表示有 sem 个资源可用 sem = 0 表示无资源可用 sem < 0 则|sem|表示 sem 等待队列中的进程个数 P(sem):表示申请一个资源 V(sem):表示释放一个资源。 P、V操作必须成对出现,有一个 P 操作就一定有一个 V 操作 # P(sem):① 将信号量sem的值减1,即sem=sem-1;② 如果sem>=0,则该进程继续执行;否则进程进入等待队列,置为等待状态,相当于把该进程挂起,切换到非等待状态的其他进程中。 # V(sem):① 将信号量sem的值加1,即sem=sem+1;② 如果sem>0,则该进程继续执行,不唤醒队列的等待进程;否则释放等待队列中第一个等待信号量的进程,继续执行本进程。(因为将信号量加1后仍然不大于0,则表示等待队列中有阻塞的进程。)
-
-
-
进程同步与互斥的关系
-
当为互斥操作时,它们pv同处于同一进程,信号量初始值为1
当为同步操作时,则pv不在同一进程中出现,信号量初始值为0 -
进程的互斥实际上是进程同步的一种特殊情况。
-
进程互斥是进程间竞争共享资源的使用权,这种竞争没有固定的必然联系,哪个进程竞争到使用权就归那个进程使用,直到不需要使用时再归还;不允许两个以上的共享该资源的并发进程同时进入临界区称为互斥。
-
而进程同步则是因直接制约而互相合作,互相等待,使得各进程按一定的顺序、速度运行的过程。
- 涉及共享资源的并发进程间有一种必然的联系,当进程必须同步时,即使无进程在使用共享资源时,那么尚未得到同步消息的进程也不能去使用这个资源。
-
4.2 信号量机制实现进程互斥
4.3 信号量机制实现进程同步
- 参考文章(公交车司机和售票员实现进程同步的例子:https://blog.csdn.net/wuxy720/article/details/78936912?utm_source=app)
4.4 共享内存
- 共享内存(Shared memory) :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。
- 这种方式需要依靠某种同步操作,如互斥锁和信号量(用来同步对共享内存的访问,防止多个线程同时操作)等。可以说这是最有用的进程间通信方式。
- 共享内存是最快的一种进程间通信,因为进程是直接对内存进行存取。
5. 套接字
- 套接字(Sockets) : 此方法主要用于在客户端和服务器之间通过网络进行通信。它能用于不同计算机之间的不同进程间通信。
- 套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
六. 操作系统实现线程同步的方式
- 线程同步可以使线程安全,可以保证多个线程访问数据的一致性,避免关键资源使用冲突,结果不一致等,实现多线程并发编程
- 操作系统一般有三种方式让线程同步
- 1)互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
- 2)信号量(Semphares) :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
- 3)事件(Event):
wait()
方法通常被用于线程间交互/通信,wait()
方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()
或者notifyAll()
方法。- 通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较
七. 死锁是什么?产生死锁四个的条件?如果解决?(见java并发面试)
- 不同的是,进程申请资源时,如果这时资源被其他进程占用时,那么这个进程进入等待状态(waiting),而线程当资源被其他资源占用时,进入阻塞状态(blocked)
八. 进程的调度算法
为了确定首先执行哪个进程以及最后执行哪个进程以实现最大 CPU 利用率,计算机科学家已经定义了一些算法,它们是:
- 先到先服务(FCFS)调度算法 : 从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
- 短作业优先(SJF)的调度算法 : 从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
- 时间片轮转调度算法 : 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称 RR(Round robin)调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
- 多级反馈队列调度算法 :前面介绍的几种进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程 。多级反馈队列调度算法既能使高优先级的作业得到响应又能使短作业(进程)迅速完成。,因而它是目前被公认的一种较好的进程调度算法,UNIX 操作系统采取的便是这种调度算法。
- 优先级调度 : 为每个流程分配优先级,首先执行具有最高优先级的进程,依此类推。具有相同优先级的进程以 FCFS 方式执行。可以根据内存要求,时间要求或任何其他资源要求来确定优先级。
九. 操作系统内存管理
1. 操作系统的内存管理主要是干什么的?
- 操作系统的内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情。
2. 常见的几种内存管理机制
- 内存管理分为两种方式:连续分配管理方式和非连续分配管理方式
- 连续分配管理方式是指为一个用户程序分配一个连续的内存空间,常见的如 块式管理 。
- 非连续分配管理方式允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理 和 段式管理以及段页式管理。
- 块式管理 : 远古时代的计算机操系统的内存管理方式。将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为碎片。
- 页式管理 :把主存分为大小相等且固定的一页一页的形式,页较小,相对相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
- 页帧又称为物理页面,是指把物理空间划分为大小相同的基本分配单元
- 页面又称为逻辑页面,是指把逻辑地址空间划分为大小相同的基本分配单元。
- 为了方便,帧与页的基本大小相同,因此页内偏移等于帧内偏移; 但页号不等于帧号。因此只需要维护页号到帧号的映射关系就行了,这就是页表的作用。
- 段式管理 : 页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义。 段式管理把主存分为一段段的,每一段的空间又要比一页的空间小很多 。但是,最重要的是段是有实际意义的,每个段定义了一组逻辑信息,例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等,而若干个段组成进程的逻辑地址空间。 段式管理通过段表对应逻辑地址和物理地址。
- 段页式管理:段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若干页,也就是说 段页式管理机制 中段与段之间以及段的内部的都是离散的。
3. 页式管理机制的快表和多级页表
-
首先需要了解页式存储管理的两个问题:
- 第一,访问一个单元需要两次内存访问(先读页表项,再读数据),这是性能问题,我们需要逻辑(虚拟)地址到物理地址的转换要快!!!
- 第二,如果逻辑(虚拟)地址空间比较大,而页面的基本单元较小,那么一个页表的大小会很大,这个是额外空间消耗问题。
-
快表!!!!
-
为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。作为页表的 Cache,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存。有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。
使用快表之后的地址转换流程是这样的:
- 根据虚拟地址中的页号查快表;
- 如果该页在快表中,直接从快表中读取相应的物理地址;
- 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
- 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。
-
多级页表
- 引入多级页表的主要目的是:解决页表大小过大
- 1)使用多级页表会发现页表占用的内存空间更少,这一切都要归功于对局部性原理的充分应用
- 2)同时也为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景。
- 引入多级页表的主要目的是:解决页表大小过大
4. 分页机制和分段机制的共同点和区别
- 共同点
- 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
- 页和段都是离散存储的(非连续管理方法),所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的,但是页和页之间、段和段之间的内存不是连续的
- 区别
- 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
- 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。
5. 区分逻辑(虚拟)地址和物理地址
- 我们编程一般只有可能和逻辑地址打交道,逻辑地址指的是机器语言指令中,用来指定一个操作数或者是一条指令的地址,比如在 C 语言中,指针里面存储的数值就可以理解成为内存里的一个地址,这个地址也就是我们说的逻辑地址,逻辑地址由操作系统决定。物理地址指的是真实物理内存中地址,更具体一点来说就是内存地址寄存器中的地址。物理地址是内存单元真正的地址。
6. 了解CPU寻址吗?为什么需要虚拟地址空间?
-
现代处理器使用的是一种称为 虚拟寻址(Virtual Addressing) 的寻址方式。使用虚拟寻址,CPU 需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。 实际上完成虚拟地址转换为物理地址转换的硬件是 CPU 中含有一个被称为 内存管理单元(Memory Management Unit, MMU) 的硬件。
-
!!!如果没有虚拟地址空间的时候,程序都是直接访问和操作的都是物理内存。而这会产生一些问题
- 1)进程地址空间不隔离,没有权限保护。用户程序可以访问任意内存,所以一个进程可以修改其他进程的数据,可能对操作系统造成伤害
- 2)会给同时运行多个程序造成困难。
- 3)内存使用效率低,当内存空间不足时,要将其他程序暂时拷贝到硬盘,然后将新的程序装入内存运行。
由于大量的数据装入装出,内存使用效率会十分低下。
-
通过虚拟地址访问内存有以下优势:
- 1)虚拟内存为每个进程提供了一个一致的、私有的地址空间,不同进程使用的虚拟地址彼此隔离。所以一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。
- 2)同时每个进程拥有一片连续完整的虚拟地址空间(内存空间)。这样会更加有效地管理内存并减少出错。
- 3)通过虚拟内存可以让程序拥有超过系统物理内存大小的可用内存空间
- 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
- 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。
十. 虚拟内存
1. 什么是虚拟内存
- 我们平时使用电脑特别是 Windows 系统的时候太常见了。很多时候我们使用点开了很多占内存的软件,这些软件占用的内存可能已经远远超出了我们电脑本身具有的物理内存。为什么可以这样呢?
- 因为 虚拟内存 的存在,通过 虚拟内存 可以让程序拥有超过系统物理内存大小的可用内存空间。虚拟内存为每个进程提供了一个一致的、私有的地址空间(虚拟地址空间),这个空间被分为大小相等的多个块,称为页(Page),每个页都是一段连续的地址,这些页会被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序,虚拟内存允许执行进程不必完全在内存中,虚拟内存可以 把内存扩展到硬盘空间,当程序引用到一部分在物理内存中的地址空间时,由硬件立刻进行必要的映射;当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的命令,从而让程序拥有超过系统物理内存大小的可用内存空间。
- 同时每个进程拥有一片连续完整的内存空间。这样会更加有效地管理内存并减少出错。
2. 局部性原理
-
局部性原理是虚拟内存技术的基础,正是因为程序运行具有局部性原理,才可以只装入部分程序到内存就开始运行。
-
局部性原理表现在以下两个方面:
- 时间局部性 :如果程序中的某条指令一旦执行,不久以后该指令可能再次执行;如果某数据被访问过,不久以后该数据可能再次被访问。产生时间局部性的典型原因,是由于在程序中存在着大量的循环操作。
- 空间局部性 :一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,这是因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式簇聚存储的。
时间局部性是通过将近来使用的指令和数据保存到高速缓存存储器中,并使用高速缓存的层次结构实现。空间局部性通常是使用较大的高速缓存,并将预取机制集成到高速缓存控制逻辑中实现。虚拟内存技术实际上就是建立了 “内存一外存”的两级存储器的结构,利用局部性原理实现髙速缓存。
3.虚拟内存技术的实现
虚拟内存的实现有以下三种方式:
- 请求分页存储管理 :建立在分页管理之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。请求分页存储管理系统中,在作业开始运行之前,仅装入当前要执行的部分段即可运行。假如在作业运行的过程中发现要访问的页面不在内存,则由处理器通知操作系统按照对应的页面置换算法将相应的页面调入到主存,同时操作系统也可以将暂时不用的页面置换到外存中。
- 请求分段存储管理 :建立在分段存储管理之上,增加了请求调段功能、分段置换功能。请求分段储存管理方式就如同请求分页储存管理方式一样,在作业开始运行之前,仅装入当前要执行的部分段即可运行;在执行过程中,可使用请求调入中断动态装入要访问但又不在内存的程序段;当内存空间已满,而又需要装入新的段时,根据置换功能适当调出某个段,以便腾出空间而装入新的段。
- 请求段页式存储管理
这里多说一下?很多人容易搞混请求分页与分页存储管理,两者有何不同呢?
请求分页存储管理建立在分页管理之上。他们的根本区别是是否将程序全部所需的全部地址空间都装入主存,这也是请求分页存储管理可以提供虚拟内存的原因,我们在上面已经分析过了。
它们之间的根本区别在于是否将一作业的全部地址空间同时装入主存。请求分页存储管理不要求将作业全部地址空间同时装入主存。基于这一点,请求分页存储管理可以提供虚存,而分页存储管理却不能提供虚存。
不管是上面那种实现方式,我们一般都需要:
- 一定容量的内存和外存:在载入程序的时候,只需要将程序的一部分装入内存,而将其他部分留在外存,然后程序就可以执行了;
- 缺页中断:如果需执行的指令或访问的数据尚未在内存(称为缺页或缺段),则由处理器通知操作系统将相应的页面或段调入到内存,然后继续执行程序;
- 虚拟地址空间 :逻辑地址到物理地址的变换。
4. 页面置换算法
地址映射过程中,若在页面中发现所要访问的页面不在内存中,则发生缺页中断 。
缺页中断 就是要访问的页不在主存,需要操作系统将其调入主存后再进行访问。 在这个时候,被内存映射的文件实际上成了一个分页交换文件。
当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来选择淘汰哪一页的规则叫做页面置换算法,我们可以把页面置换算法看成是淘汰页面的规则。
- OPT 页面置换算法(最佳页面置换算法) :最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。一般作为衡量其他置换算法的方法。
- FIFO(First In First Out) 页面置换算法(先进先出页面置换算法) : 总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
- LRU (Least Currently Used)页面置换算法(最近最久未使用页面置换算法) :LRU算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 T,当须淘汰一个页面时,选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。
- LFU (Least Frequently Used)页面置换算法(最少使用页面置换算法) : 该置换算法选择在之前时期使用最少的页面作为淘汰页。