互联网面试知识点总结(二)- 操作系统篇

互联网面试知识点总结(二)- 操作系统篇

  • ******************************* 进程调度 *****************************
  • 一. 进程的状态
  • 二. 进程和线程的区别
  • 三. 线程共享哪些变量
  • ******************************* 内存管理 *****************************
  • ******************************* 文件系统 *****************************
  • ****************************** Linux命令 ****************************
  • 什么是操作系统
  • 并发和并行
  • 用户态和内核态
  • 系统调用
  • 操作系统创建一个新进程的过程?
  • 操作系统终止进程的过程?
  • 为什么有了进程还要引入线程
  • 进程间通信方式
  • 常用线程模型
  • Linux四种锁机制
  • 线程间同步的方式
  • CPU调度评价指标
  • CPU调度算法
  • 实现临界区互斥方法
  • 死锁概念
  • 死锁的必要条件
  • 解决死锁的办法
  • 内存管理机制
  • 内存管理方式
  • 连续内存分配算法
  • 分页存储的几个基本概念
  • 快表
  • 多级页表
  • 页式管理与段式管理的异同点
  • 内存碎片
  • 基本逻辑地址到物理地址的变换过程如下
  • 快表中逻辑地址到物理地址的变换过程如下
  • 局部性原理表现在以下两个方面
  • 为什么要有虚拟地址空间呢?
  • 说一说Linux虚拟地址空间
  • 虚拟存储器
  • 虚拟内存技术的实现
  • 缺页中断
  • 缺页中断与其他中断区别
  • 局部页面置换算法
  • Belady现象
  • 全局页面置换算法?

******************************* 进程调度 *****************************

一. 进程的状态

进程在其生命周期内,由于系统中个进程之间的相互制约关系以及系统的运行环境的变化,使的进程的状态也在不断地发生着变化。通常进程有以下五种状态。前三种是进程的基本状态

  1. 运行状态:进程正在处理器上运行。在单处理器的环境下,每一时刻最多只有一个进程处于运行状态
  2. 就绪状态:进程已处于准备运行的状态,即进程获得了除CPU之外的一切所需资源,一旦得到处理器即可运行。
  3. 阻塞状态:又称为等待状态:进程正在等待某一事件而暂停运行,如等待某资源为可用(不包括处理器),或等待输入输出的完成,即使处理器空闲,该进程也不能运行
  4. 创建状态:进程正在被创建,尚未转到就绪状态
  5. 结束状态:进程正在从系统中消失,这可能是进程正常结束或其他原因中断退出运行

二. 进程和线程的区别

  1. 进程是对运行时程序的封装,是系统进行资源调度和分配的基本单位,实现了操作系统的并发,线程是进程的子任务,是CPU调度和分派的基本单位,用于实现进程内的并发
  2. 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程,线程依赖进程而存在
  3. 进程在执行过程中拥有独立的内存空间,而多个线程共享同一个内存空间(进程的内存空间)
  4. 在系统开销上,进程创建、撤销和切换的开销远大于线程的开销

三. 线程共享哪些变量

******************************* 内存管理 *****************************

******************************* 文件系统 *****************************

****************************** Linux命令 ****************************

什么是操作系统

  1. 操作系统(Operating System,简称OS)是管理计算机硬件与软件资源的程序,是计算机系统的内核与基石
  2. 操作系统本质上是运行在计算机上的软件程序
  3. 操作系统为用户提供一个与系统交互的操作界面
  4. 操作系统分内核与外壳(我们可以把外壳理解成围绕着内核的应用程序,而内核可以理解为能直接操作硬件的程序)
    PS:内核负责管理系统的进程、内存、设备驱动程序、文件和网络系统等等,决定着系统的性能和稳定性。是连接应用程序和硬件的桥梁。内核就是操作系统背后黑盒的核心

并发和并行

  1. 并发(concurrency):指宏观上看起来两个程序在同时运行,比如说在单核 cpu 上的多任务。但是从微观上看两个程序的指令是交织着运行的,你的指令之间穿插着我的指令,我的指令之间穿插着你的,在单个周期内只运行了一个指令。这种并发并不能提高计算机的性能,只能提高效率。
  2. 并行(parallelism):指严格物理意义上的同时运行,比如多核 cpu,两个程序分别运行在两个核上,两者之间互不影响,单个周期内每个程序都运行了自己的指令,也就是运行了两条指令。这样说来并行的确提高了计算机的效率。所以现在的 cpu 都是往多核方面发展。

用户态和内核态

用户态和内核态是操作系统的两种运行级别,两者最大的区别就是特权级不同。用户态拥有最低的特权级,内核态拥有较高的特权级。运行在用户态的程序不能直接访问操作系统内核数据结构和程序。内核态和用户态之间的转换方式主要包括:系统调用,异常和中断

系统调用

操作系统创建一个新进程的过程?

  1. 为新进程分配唯一一个进程标识符,并申请一个空白的PCB。
  2. 为进程分配资源,为新进程的程序和数据,以及用户占分配必要的空间。
  3. 初始化PCB,主要包括初始化标识信息、初始化处理器状态信息和初始化处理器控制信息,以及设置进程的空闲及
  4. 如果进程就绪队列能够接纳新进程,就将新进程插入到就绪队列,等待被调度运行

操作系统终止进程的过程?

  1. 根据被终止进程的标示符,检索PCB,从中读出该进程的状态
  2. 若被终止进程处于执行状态,立即终止该进程的执行,将处理器资源分配给其他进程
  3. 若该进程还有子进程,则应将其所有子进程终止
  4. 将该进程所拥有的资源、或归还给父进程或归还给操作系统
  5. 将该PCB从所在队列(链表)中删除

为什么有了进程还要引入线程

  1. 从资源上来讲,线程是一种非常"节俭"的多任务操作方式。在 linux 系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式
  2. 从切换效率上来讲,运行于一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需时间也远远小于进程间切换所需要的时间。据统计,一个进程的开销大约是一个线程开销的 30 倍左右
  3. 从通信机制上来讲,线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进城下的线程之间贡献数据空间,所以一个线程的数据可以直接为其他线程所用,这不仅快捷,而且方便。

进程间通信方式

  1. 消息队列
    消息队列独立于发送与接收数据,进程终止时,消息队列及其内容并不会被删除,消息队列可以实现消息的随机查询,也可以按照消息类型读取
  2. 信号量
    信号量是一个计数器,可以用来控制多个进程对共享资源的访问,用于实现进程间的互斥和同步,而不是存储进程间的通信数据,若要进程间传递数据需要信号量结合共享内存
  3. 信号
    信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生
  4. 共享内存
    使得多个进程可以访问同一块内存,但需要依赖互斥锁和信号量
  5. 套接字
    用于不同主机之间进程间的通信
  6. 匿名管道
    匿名管道是半双工的,数据只能在一个方向上传输,只能用于具有亲缘关系的进程之间通信(父子进程或者兄弟进程)
  7. 有名管道
    有名管道可以再无关的进程之间传递信息,FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中
    详解点击传送门

常用线程模型

  1. Future 模型
    该模型通常在使用的时候需要结合 Callable 接口配合使用。Future 是把结果放在将来获取,当前主线程并不急于获取处理结果。允许子线程先进行处理一段时间,处理结束之后就把结果保存下来,当主线程需要使用的时候再向子线程索取。Callable 是类似于 Runnable 的接口,其中 call 方法类似于 run 方法,所不同的是 run 方法不能抛出受检异常没有返回值,而 call 方法则可以抛出受检异常并可设置返回值。两者的方法体都是线程执行体。
  2. fork&join 模型
    该模型包含递归思想和回溯思想,递归用来拆分任务,回溯用合并结果。 可以用来处理一些可以进行拆分的大任务。其主要是把一个大任务逐级拆分为多个子任务,然后分别在子线程中执行,当每个子线程执行结束之后逐级回溯,返回结果进行汇总合并,最终得出想要的结果。这里模拟一个摘苹果的场景:有 100 棵苹果树,每棵苹果树有 10 个苹果,现在要把他们摘下来。为了节约时间,规定每个线程最多只能摘 10 棵苹树以便于节约时间。各个线程摘完之后汇总计算总苹果树。
  3. actor 模型
    actor 模型属于一种基于消息传递机制并行任务处理思想,它以消息的形式来进行线程间数据传输,避免了全局变量的使用,进而避免了数据同步错误的隐患。actor 在接受到消息之后可以自己进行处理,也可以继续传递(分发)给其它 actor 进行处理。在使用 actor 模型的时候需要使用第三方 Akka 提供的框架。
  4. 生产者消费者模型
    生产者消费者模型都比较熟悉,其核心是使用一个缓存来保存任务。开启一个/多个线程来生产任务,然后再开启一个/多个来从缓存中取出任务进行处理。这样的好处是任务的生成和处理分隔开,生产者不需要处理任务,只负责向生成任务然后保存到缓存。而消费者只需要从缓存中取出任务进行处理。使用的时候可以根据任务的生成情况和处理情况开启不同的线程来处理。比如,生成的任务速度较快,那么就可以灵活的多开启几个消费者线程进行处理,这样就可以避免任务的处理响应缓慢的问题。
  5. master-worker 模型
    master-worker 模型类似于任务分发策略,开启一个 master 线程接收任务,然后在 master 中根据任务的具体情况进行分发给其它 worker 子线程,然后由子线程处理任务。如需返回结果,则 worker 处理结束之后把处理结果返回给 master。

Linux四种锁机制

  1. 互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象。当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒

  2. 读写锁:rwlock,分为读锁和写锁。处于读操作时,可以允许多个线程同时获得读操作。但是同一时刻只能有一个线程可以获得写锁。其它获取写锁失败的线程都会进入睡眠状态,直到写锁释放时被唤醒。 注意:写锁会阻塞其它读写锁。当有一个线程获得写锁在写时,读锁也不能被其它线程获取;写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)。适用于读取数据的频率远远大于写数据的频率的场合。

  3. 自旋锁:spinlock,在任何时刻同样只能有一个线程访问对象。但是当获取锁操作失败时,不会进入睡眠,而是会在原地自旋,直到锁被释放。这样节省了线程从睡眠状态到被唤醒期间的消耗,在加锁时间短暂的环境下会极大的提高效率。但如果加锁时间过长,则会非常浪费 CPU 资源。

  4. RCU:即 read-copy-update,在修改数据时,首先需要读取数据,然后生成一个副本,对副本进行修改。修改完成后,再将老数据 update 成新的数据。使用 RCU 时,读者几乎不需要同步开销,既不需要获得锁,也不使用原子指令,不会导致锁竞争,因此就不用考虑死锁问题了。而对于写者的同步开销较大,它需要复制被修改的数据,还必须使用锁机制同步并行其它写者的修改操作。在有大量读操作,少量写操作的情况下效率非常高?

线程间同步的方式

  1. 锁机制:包括互斥锁、条件变量、读写锁
    互斥锁提供了以排他方式防止数据结构被并发修改的方法。
    读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
    条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
  2. 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
  3. 信号机制(Signal):类似进程间的信号处理

CPU调度评价指标

  1. CPU利用率
    CPU忙碌时间占总时间比例
  2. 系统吞吐量
    系统吞吐量表示单位时间内CPU处理的数量
  3. 周转时间
    周转时间是指从进程创建提交到进程结束所经历的时间,包括进程等待、在就绪队列中排队、在处理器上运行以及上下文切换操作所花费的时间的总和
  4. 等待时间
    等待时间是指进程处于等处理器状态时间之和
    (5) 响应时间
    响应时间是指从用户提交请求到系统首次产生响应所有的时间。在交互式系统中,周转时间不可能是最好的评测准则,一般采用响应时间作为衡量调度算法的重要准则之一。从用户的角度来看,调度策略应尽量降低响应时间,使响应时间处在用户能够接受的范围之内

CPU调度算法

  1. FIFS先来先服务调度算法
    FIFS调度算法属于不可抢占算法。从表面上看,它对所有作业都是公平的,但若一个长作业先到达系统,就会使后面许多短作业等待很长时间,因此它不能作为分时系统和实时系统的主要调度策略。但它常被结合在其他调度策略中使用,FIFS算法简单,但是效率低;有利于长作业,不利于短作业;有利于CPU繁忙型作业而不利于IO繁忙型作业
  2. SJF短作业优先调度算法
    SJF优先调度算法,则是从就绪队列中选择一个估计运行时间最短的进程,将处理机分配给它,使之立即执行,但该算法对长作业非常不友好,该算法完全未考虑作业的紧迫程度,由于作业的长短只根据用户所提供的估计执行时间而定的,而用户又可能会有意或无意的缩短其作业的估计运行时间,致使该算法不一定能真正做到算作业优先调度,但是,SJF调度算法的平均等待时间、平均周转时间最少。
  3. 优先级调度算法
    在进程调度中,优先级调度算法每次从就绪队列中选择优先级最高的进程,将处理机分配给它,使之投入运行
    根据新的更高优先级进程能否抢占正在执行的进程,可将该调度算法分为:
    • 非剥夺式优先级调度算法。当某一个进程正在处理机上运行时,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在运行的进程继续运行,直到由于其自身的原因而主动让出处理机时(任务完成或等待事件),才把处理机分配给更为重要或紧迫的进程。
    • 剥夺式优先级调度算法。当一个进程正在处理机上运行时,若有某个更为重要或紧迫的进程进入就绪队列,则立即暂停正在运行的进程,将处理机分配给更重要或紧迫的进程。
    根据进程创建后其优先级是否可以改变,可以将进程优先级分为以下两种:
    • 静态优先级。优先级是在创建进程时确定的,且在进程的整个运行期间保持不变。确定静态优先级的主要依据有进程类型、进程对资源的要求、用户要求。
    • 动态优先级。在进程运行过程中,根据进程情况的变化动态调整优先级。动态调整优先级的主要依据为进程占有CPU时间的长短、就绪进程等待CPU时间的长短
  4. 高响应比优先调度算法
    根据比率:R=(w+s)/s (R为响应比,w为等待处理的时间,s为预计的服务时间),是对FCFS调度算法和SJF调度算法的一种综合平衡,同时考虑每个进程的等待时间和估计的运行时间。在每次进行进程调度时,先计算就绪队列队列中每个作业的响应比,从中选出响应比最高的进程投入运行
  5. 时间片轮转调度算法
    系统将所有就绪进程按到达时间的先后次序排成一个队列,进程调度程序总是选择就绪队列中第一个进程执行,即先来先服务的原则,但仅能运行一个时间片,如100ms。在使用完一个时间片后,即使进程并未完成其运行,它也必须释放出(被剥夺)处理机给下一个就绪的进程,而被剥夺的进程返回到就绪队列的末尾重新排队,等候再次运行。在时间片轮转调度算法中,时间片的大小对系统性能的影响很大。如果时间片足够大,以至于所有进程都能在一个时间片内执行完毕,则时间片轮转调度算法就退化为先来先服务调度算法。如果时间片很小,那么处理机将在进程间过于频繁切换,使处理机的开销增大,而真正用于运行用户进程的时间将减少。因此时间片的大小应选择适当
  6. 多级反馈队列调度算法
    多级反馈队列调度算法主要是时间片轮转调度算法和优先级调度算法的综合和发展。通过动态调整进程优先级和时间片大小,多级反馈队列调度算法可以兼顾多方面的系统目标
    • 应设置多个就绪队列,并为各个队列赋予不同的优先级,第1级队列的优先级最高,第2级队列次之,其余队列的优先级逐次降低。
    • 赋予各个队列中进程执行时间片的大小也各不相同,在优先级越高的队列中,每个进程的运行时间片就越小。例如,第2级队列的时间片要比第1级队列的时间片长一倍, ……第i+1级队列的时间片要比第i级队列的时间片长一倍。
    • 当一个新进程进入内存后,首先将它放入第1级队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第2级队列的末尾,再同样地按FCFS 原则等待调度执行;如果它在第2级队列中运行一个时间片后仍未完成,再以同样的方法放入第3级队列……如此下去,当一个长进程从第1级队列依次降到第 n 级队列后,在第 n 级队列中便釆用时间片轮转的方式运行。
    • 仅当第1级队列为空时,调度程序才调度第2级队列中的进程运行;仅当第1 ~ (i-1)级队列均为空时,才会调度第i级队列中的进程运行。如果处理机正在执行第i级队列中的某进程时,又有新进程进入优先级较高的队列(第 1 ~ (i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i级队列的末尾,把处理机分配给新到的更高优先级的进程

实现临界区互斥方法

  1. 硬件实现方法
    当一个进程正在使用处理器执行他的临界区代码时,要防止去其他进程在进入其临界区访问的最简单方法就是禁止一切中断的发生,或称之为屏蔽中断、关中断。因为CPU只有在发生中断时引起进程的调度和切换,这样屏蔽中断就能保证当前运行进程将临界区代码顺利的执行完,然后再开中断。这种方法限制了处理器交替执行程序的能力,因此执行的效率将会明显降低。对内核来说,当它执行更新变量或列表的几条指令期间关中断是很方便的,但将关中断的权力交给用户则很不明智,若一个进程关中断之后不再打开终端,则系统可能会因此终止
  2. 软件实现方法:操作复杂
  3. 原子指令方法:由硬件逻辑实现,该指令不能被中断,包括TestAndSet指令和Swap指令

死锁概念

多个并发进程因争夺系统资源而产生相互等待的现象,原因是系统资源有限,进程推进顺序不合理

死锁的必要条件

  1. 互斥条件:进程要求对所分配的资源进行排他性控制,即在一段时间内某资源仅为一个进程所占用。此时若有其他进程请求该资源,则请求进程只能等待。
  2. 不抢占条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放。
  3. 请求条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
  4. 循环等待条件:存在一种进程资源的循环等待链,连中每一个进程已获得的资源同时被链中下一个进程所请求

解决死锁的办法

  1. 资源一次性分配:一次性分配所有资源,这样就不会再有请求了:(破坏请求条件)
  2. 只要有一个资源得不到分配,也不给这个进程分配其他的资源:(破坏请求条件)
  3. 可抢占资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可抢占条件)
  4. 资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

内存管理机制

简单分为连续分配管理方式和非连续分配管理方式这两种。连续分配管理方式是指为一个用户程序分配一个连续的内存空间,常见的如块式管理 ;非连续分配管理方式允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理和段式管理

内存管理方式

  1. 块式管理 :将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为碎片
  2. 页式管理 :在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的页框,程序加载时,可以将任意一页放入内存中任意一个页框,这些页框不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)
  3. 段式管理 :在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)
  4. 段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若干页,也就是说段页式管理机制中段与段之间以及段的内部的都是离散的

连续内存分配算法

  1. 首次适应算法:空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区
  2. 最佳适应算法:空闲分区按容量递增形成分区链,找到第一个能满足要求的空闲分区
  3. 最坏适应算法:有称最大适应算法,空闲分区以容量递减次序链接。找到第一个能满足要求的空闲分区,也就是挑选最大的分区
  4. 临近适应算法:又称循环首次适应算法,由首次适应算法演变而成。不同之处是分配内存时从此查找结束的位置开始继续查找
    PS:在这几种方法中,首次适应算法不仅是最简单的,而且通常是最好和最快的。在UNIX系统的最初版本中,就是使用首次适应算法为进程分配内存空间,其中使用数组的数据结构(而非链表)来实现。不过,首次适应算法会使得内存的低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区。
    临近适应算法试图解决这一问题,但实际上,它常常会导致在内存的末尾分配空间,分裂成小碎片。它通常比首次适应算法的结果要差。最佳适应算法虽然称为最佳,但是性能通常很差,因为每次最佳的分配会留下最小的内存块,它会产生最多的碎片。最坏适应算法与最佳适应算法相反,选择最大的可用块,这看起来最不容易产生碎片,但是却把最大的连续内存划分开,会很快导致没有可用的大的内存块,因此性能非常差。

分页存储的几个基本概念

  1. 页面和页面大小
    进程中的块称为页,内存中的块称为页框。外存也以同样单位划分,直接称为块。进程在执行时需要申请主存空间,就是要为每个页面分配主存中的可用页框,这就产生了页和页框的一一对应。为了方便地址转换,页面大小应是2的整数幂。同时页面大小应当适中。如果页面太小,会是进程的页面数过多,这样页表就过长,占用大量内存,而且也会增加硬件地址转换的开销,降低页面换入换出的效率。页面过大又会是页面碎片过大,降低内存利用率。所以页面的大小应该适中,考虑到空间效率和时间效率
  2. 地址结构
    分页存储管理的地址长度包含两部分:前一部分为页号,后一部分为页内偏移量W。地址长度为32位,其中0 ~ 11为页内地址,即每页大小为4KB;12~31位为页号
  3. 页表
    为了便于在内存中找到进程的每个页面所对应的物理块,系统为每个进程建立一张页表,记录页面在内存中对应的物理块号,页表一般存放在内存中

快表

为了解决逻辑地址到物理地址的转换速度,操作系统在页表方案基础之上引入了快表来加速虚拟地址到物理地址的转换。其中的内容是页表的一部分或者全部内容,位置在cache中,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时CPU要访问两次主存。有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度

多级页表

由于引入了分页管理,进程在执行时不需要将所有页调入内存页框中,而只要将保存有映射关系的页表调入内存即可。但是我们仍然需要考虑页表的大小。如果页表太大,肯定是降低了内存利用率的;从另一方面来说,程序所有的页表项也并不需要同时保存在内存中,因为在大多数情况下,映射所需要的页表都再也表的同一个页面中。我们将页表映射的思想进一步延伸,就可以得到二级分页:将页表的10页空间也进行地址映射,建立上一级页表,所以上一级页表只需要一页就足够。在进程执行时,只需要将这一页上一级页表调入内存即可,进程的页表和进程本身的页面,可以在后面的执行中再调入内存

页式管理与段式管理的异同点

  1. 共同点 :
    • 分页机制和分段机制都是为了提高内存利用率,减少内存碎片
    • 页和段都是离散存储的,但是每个页和段中的内存是连续的
  2. 不同点
    • 段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的 ;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的
    • 段的大小不固定,有它所完成的功能决定;页大大小固定,由系统决定
    • 段地址是二维地址,包括段名和段内地址;页地址是一维地址

内存碎片

  1. 内部碎片
    内部碎片就是已经被分配出去却不能被利用的内存空间,内部碎片是处于区域内部或页面内部的存储块,占有这些区域或页面的进程并不使用这个存储块
  2. 外部碎片
    外部碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域

基本逻辑地址到物理地址的变换过程如下

  1. 地址变换机构自动将有效地址分为页号和页内偏移量两部分,再用页号去检索页表。在执行检索之前,先将页号与页表长度比较,如果页号大于或等于页表长度,则表示地址越界并中断。
  2. 若未越界,则将页表始址与页号和页表项长度的乘积相加,便得到该表项在页表中的位置,于是可从中得到该页的物理块号。
  3. 与此同时,在将有效地址中的页内偏移量送入物理地址寄存器的块内地址字段中

快表中逻辑地址到物理地址的变换过程如下

  1. CPU给出有效地址后,由硬件进行地址转换,并将页号送入高速缓存寄存器,并将此页号与快表中的所有页号同时进行比较。
  2. 如果有找到匹配的页号,说明索要访问的页表项在快表中,则可以直接从中读出该页对应的页框号,送到物理地址寄存器。这样存取数据可以直接一次访存实现。
  3. 如果没有找到,则需要访问主存中的页表,在读出页表项后,应同时将其存入快表中,以供后面可能的再次访问。但是如果快表已满,就必须按照一定的算法对其中旧的页表项进行替换。注意,有些处理器设计为快表和主存同时查找,如果在快表中匹配成功则终止主存中的查找

局部性原理表现在以下两个方面

  1. 时间局部性:如果程序中的某条指令一旦执行,则不久以后该指令可能再次执行;如果某数据被访问过,则不久以后该数据可能再次被访问,产生时间局部性的典型原因,是由于在程序中存在着大量的循环操作。
  2. 空间局部性:一旦程序访问量某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,其典型情况便是程序的顺序执行

为什么要有虚拟地址空间呢?

  1. 如果用户程序可以访问任意内存,寻址内存的每个字节,这样就很容易(有意或者无意)破坏操作系统,造成操作系统崩溃,想要同时运行多个程序特别困难,比如你想同时运行两个微信,第一个微信在运行的时候给内存地址1xxx赋值后,第二个微信也同样给内存地址1xxx赋值,那么两个微信对内存的赋值就会覆盖另一个所赋的值,这就造成了微信这个程序就会崩溃。
  2. 通过虚拟地址访问内存有以下优势:
    • 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
    • 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。
    • 不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存

说一说Linux虚拟地址空间

为了防止不同进程同一时刻在物理内存中运行而对物理内存的争夺和践踏,采用了虚拟内存。虚拟内存技术使得不同进程在运行过程中,它所看到的是自己独自占有了当前系统的 4G 内存。所有进程共享同一物理内存,每个进程只把自己目前需要的虚拟内存空间映射并存储到物理内存上。 事实上,在每个进程创建加载时,内核只是为进程“创建”了虚拟内存的布局,具体就是初始化进程控制表中内存相关的链表,实际上并不立即就把虚拟内存对应位置的程序数据和代码(比如.text .data 段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射就好(叫做存储器映射),等到运行到对应的程序时,才会通过缺页异常,来拷贝数据

虚拟存储器

在程序装入时,可以将程序的一部分装入内存,而将其与部分留在外存,就可以启动程序执行。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换到外存上,从而腾出空间存放将要调入内存的信息。这样,计算机好像为用户提供了一个比实际内存大的多的存储器,成为虚拟存储器

虚拟内存技术的实现

虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。 虚拟内存的实现有以下三种方式:

  1. 请求分页存储管理 :建立在基本分页系统基础之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。
  2. 请求分段存储管理
  3. 请求段页式存储管理

缺页中断

在请求分页系统中,每当所要访问的页面不在内存时,便产生一个缺页中断,请求操作系统将所缺的页调入内存。缺页中断作为中断同样要经历诸如:保护CPU环境、分析中断原因、转入缺页中断处理程序进行处理、恢复CPU环境等几个步骤

缺页中断与其他中断区别

  1. 在指令执行期间产生和处理中断信号,而非一条指令执行完后。
  2. 一条指令在执行期间,可能产生多次缺页中断

局部页面置换算法

  1. OPT页面置换算法(最佳页面置换算法)
    理想情况,不可能实现,一般作为衡量其他置换算法的方法。
  2. FIFO页面置换算法(先进先出页面置换算法)
    总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
  3. LRU页面置换算法(最近未使用页面置换算法)?
    LRU(Least Currently Used)算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间T,当须淘汰一个页面时,选择现有页面中其T值最大的,即最近最久未使用的页面予以淘汰。
  4. LFU页面置换算法(最少使用页面排序算法)?
    LFU(Least Frequently Used)算法会让系统维护一个按最近一次访问时间排序的页面链表,链表首节点是最近刚刚使用过的页面,链表尾节点是最久未使用的页面。访问内存时,找到相应页面,并把它移到链表之首。缺页时,置换链表尾节点的页面。也就是说内存内使用越频繁的页面,被保留的时间也相对越长
  5. CLOCK算法(近似LRU算法)
    各个页面组织形成环形链表,当页面装入内存时,访问位初始化为0,当页面被读写时,访问位置为1,当内存满了,需要换页时,从指针当前位置循环检查链表,如果访问为0,在置换该页,如果访问位为1,在将访问位置为0,然后在将指针移动到下一个页面,直到找到可置换的页面

Belady现象

  1. 现象解释:局部置换算法给每个进程分配的物理页面数是一定的,当缺页次数过高时,就需要增加分配物理页面数,但此时并不一定会降低缺页次数(主要是置换算法采用的是FIFO算法等)。
  2. 原因:FIFO算法的置换特征与进程访问内存的动态特征是有矛盾的,违背了局部性原理

全局页面置换算法?

  1. 工作机置换算法
  2. 缺页率置换算法

你可能感兴趣的:(linux,操作系统,多线程,cpu,多进程)