面试基础:一次搞懂操作系统的核心问题

本文详细解析了操作系统的基础知识,包括进程与线程的定义、状态及调度,深入探讨了内存管理的段页式机制和虚拟内存的工作原理,以及页面置换算法。通过对这些核心概念的阐述,帮助读者在面试中更好地理解和解答相关问题。
摘要由CSDN通过智能技术生成

文章首发于公众号:听涛记,可扫码关注,获取更多校招求职干货

欢迎关注:听涛记,真正的校招求职干货

一、定义与基本概念

操作系统(Operating System,简称OS)是连接计算机硬件与软件的中间层。分内核与外壳,内核用于操作和管理硬件,用户态连接上部的应用程序。

因此,操作系统分为两种状态:

  • 用户态:系统权限低,只可读取应用程序的数据
  • 内核态:系统权限高,几乎可以访问系统的任何资源,不受限制。

系统调用:运行在用户态的应用程序,如果需要进行与内核态级别的资源有关的操作,都必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。
系统调用类别:

  • 设备管理。完成设备的请求或释放,以及设备启动等功能。
  • 文件管理。完成文件的读、写、创建及删除等功能。
  • 进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。
  • 进程通信。完成进程之间的消息传递或信号传递等功能。
  • 内存管理。完成内存的分配、回收以及获取作业占用内存区大小及地址等功能。

因此,操作系统主要负责两块的内容:进程管理、内存管理。即事务管理,资源管理

二、进程与线程

定义

进程:操作系统的基本单元。进程与进程之间彼此独立。

线程:一个进程在执行过程中会产生多个线程,线程是进程更小的执行单元,因此开销更小。只有当所有线程都完成时,整个进程才认为完成。多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器、虚拟机栈 和 本地方法栈。同一进程中的线程由于共享资源,会互相影响,不利于资源管理和保护。

打个比方:进程是大哥,线程是小弟,一个大哥可以有多个小弟。大哥有自己的地盘,小弟们在大哥的地盘上分头去做不同的事情。大哥盘子大,规矩多,耗时间,但是大哥的马仔比较灵活,这个马仔不听话,换个马仔来干。大哥之间办事的时候,由于在不同地盘,得用大哥大通信,但是小弟们靠得近,有事喊一声,或者遇到事情跟大哥请示一下就行。当然小弟之间也可能打架,这时候也需要定一些规则。

区别:

  • 资源:线程是进程的细化,一个进程一般对应多个线程。进程拥有资源,线程只可访问所属进程的资源
  • 开销:进程在创建、切换、销毁时开销较大,而同一进程中的线程由于共享大部分资源,因此开销小
  • 通信:进程的通信需要依靠同步和互斥手段,以保证数据一致性,而线程可以直接操作同一进程中的数据资源完成通信

进程状态

一个进程的整个生命周期一般会经过以下五种状态,但主要关注的是就绪、运行、阻塞三个状态

  • 创建态(new) :进程正在被创建,尚未到就绪状态。
  • 就绪态(ready) :进程已处于准备运行状态,即进程获得了除了CPU之外的一切所需资源,一旦得到处理器资源(处理器分配的时间片)即可运行。
  • 运行态(running) :进程正在处理器上上运行(单核CPU下任意时刻只有一个进程处于运行状态)。
  • 阻塞态(waiting) :进程正在等待某一事件而暂停运行。如等待某资源为可用或等待 IO 操作完成。即使处理器空闲,该进程也不能运行。
  • 终止态(terminated) :进程正在从系统中消失。可能是进程正常结束或其他原因中断退出运行。
    在这里插入图片描述
    注意:
  • 只有就绪态和运行态可以互相转换。就绪态的进程通过调度算法从而获得 CPU 时间,转为运行状态;而运行状态的进程,在分配给它的 CPU 时间片用完之后就会转为就绪状态,等待下一次调度。

进程调度

当有多个进程处于就绪态时,CPU该先处理哪个进程?这就涉及进程调度算法。调度分为三类场景:

批处理场景:一群人等着吃饭,每个人都要吃上,目标是总时间最短
  • 先来先服务:按时间顺序调度,有利于长进程,不利于短进程。因为短进程必须一直等待前面的长作业执行完毕才能执行,而长进程又需要执行很长时间,造成了短进程等待时间过长。
  • 短作业优先:根据进程完成所需时间升序排列,依次执行,这样总时间最优。有利于短进程,不利于长进程。当一直有短作业到来时,长作业就一直得不到调度
  • 最短剩余时间优先:抢占式调度,CPU在执行某个进程时,如果又来了一个新进程,新进程的完成时间比当前进程剩余时间还短时,当前进程被挂起,CPU转而执行新进程
交互式场景:来一个安排一个,目标是响应时间最短
  • 时间片轮转:就绪的进程按照时间排队,CPU依次从队首进程并分配一个时间段,进程执行时间超过规定的时间片后,无论是否完成,都会转为就绪态放入队尾。因此,时间片的大小很关键,如果时间片太小,进程频繁切换,总体效率会很差,但如果时间片过长,那响应性就会变差
  • 优先级调度:每个进程按照优先级排序依次执行。进程的优先级可以随着等待时间的增加而增加,避免某个进程长时间得不到响应
  • 多级反馈队列:时间片轮转时,由于时间片长度固定,因此只是线性执行。比如:一个进程的完成需要100个时间单位,如果时间片为1个时间单位,那么该进程的完成,需要100次切换。多级队列的优化在于,进程为指数执行。进程得到的时间片是分级的,如第一次为1,第二次为2,第三次为4,以此类推,那么该进程则只需要切换7次便可完成。实现方式为,进程依次进入不同的优先级的队列。

进程间通信

  1. 管道:又称为匿名管道,存在与内存中
  • 只用于具有亲缘关系的父子进程间或者兄弟进程之间的通信
  • 无格式,先进先出,单向
  1. 有名管道: 存在磁盘中
  • 可用于本机任意两个进程的通信
  • 无格式,先进先出,单向
  1. 信号:通知接收进程某个事件的发生
  • 用于快速响应
  • 只有一种格式类型
  1. 消息队列:存在内核中,只有在内核重启或者显式删除,消息队列才会被真正的删除。
  • 消息队列克服了信号信息量少,管道只能承载无格式字节流以及缓冲区大小受限等局限
  • 消息具有特定的格式和优先级,可以顺序读,也可以按照类型或优先级读取
  • 消息队列独立于读写进程,读写可以异步。即写入的时候可以没有读进程,读的时候可能写进程已经结束。
  1. 信号量 :信号量是一个计数器,用于多进程对共享数据的访问,用于进程间同步
  2. 共享内存 :多个进程共享同一块内存空间
  • 最快的进程间通信方式
  • 多个进程可以操作共享内存,因此必须进行同步
  1. 套接字 : 用于不同主机之间的进程进行双向通信

举例:

cat demo.log | grep "abc" 

该条linux指令中的 | 便是管道,它的作用就是把前一条命令的输出作为后一条命令的输入。上面的指令,即为将cat demo.log的输出,作为grep "abc"的输入。这就建立了两条指令间的通信关系,由于这个竖线没有名字,因此称为匿名管道。可以看到,这种管道是单向的,只能把第一个命令的输出作为第二个命令的输入。
有名管道,又称为FIFO,一个进程向管道写入数据,然后会阻塞等待,直到另外一个进程从管道中读出数据,阻塞的进程才会结束返回。这又称为有名管道的同步阻塞问题。因此,该通信方式效率比较低,不适合频繁通信,但优势是简单,并且保证写入的数据真的被其他进程拿走。

mkfifo  demo  //定义一个名为demo的有名管道
echo "this is a pipe" > demo   // 写数据
cat < demo  // 读数据

消息队列解决了同步阻塞的问题,例如 a 进程要给 b 进程发送消息,只需要把消息放在对应的消息队列里就行了,b 进程需要的时候再去取对应的队列里面取消息。即将同步阻塞变为异步,将读写过程解耦。但是,如果a进行要传递的数据比较大,并且a,b两个进程的通信非常频繁,那么发消息时进行的数据拷贝就非常耗时。

为了降低拷贝耗时,出现了共享内存。即a,b两个进程的虚拟空间,映射到同一个物理内存,任一进程在共享内存中的修改都会被对方感知,且无须拷贝过程。但共享内存又带来了多线程竞态问题,比如a进程要将变量改为10,而b进程要将变量改为20。这就要求进程间的同步和互斥。

信号量的本质就是一个计数器,用来实现进程之间的互斥与同步。例如信号量的初始值是 1,然后 a 进程来访问内存1的时候,我们就把信号量的值设为 0,然后进程b 也要来访问内存1的时候,看到信号量的值为 0 就知道已经有进程在访问内存1了,这个时候进程 b 就会访问不了内存1。这其实与线程安全中的互斥锁类似。

线程间同步

线程由于处于同一进程内,无需通信,只需将各个线程的状态进行同步,避免并发冲突
9. 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问
10. 信号量 :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
11. 事件 :通过通知操作的方式来保持多线程同步

三、内存管理

1. 段/页式管理

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

块式管理 :

将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块。无疑这种方式会造成较多浪费

页式管理 :

把主存分为大小相等且固定的一页一页的形式,页较小,相对相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表建立逻辑地址到物理地址的映射。

段式管理 :

段式管理把主存分为一段段的,每段构成独立的地址空间,每段的大小不一,由相应的逻辑信息组的长度决定,并且可以动态增长。段式管理通过段表建立逻辑地址到物理地址的映射。

段页式管理机制:

段页式管理机制结合了段式管理和页式管理的优点。地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页

例如:将一个人每隔50厘米切割一段,即为分页;而将一个人分割为头部、身体、腿部(有完整逻辑意义)三段,即为分段

段式存储和页式存储的共同点和区别:

共同点 :
  • 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
  • 页和段都是离散存储的,但是,每个页和段中的内存是连续的。
区别 :
  • 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
  • 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段等等,能够更好满足用户的需要。一条指令或一个操作数可能会跨越两个页的分界处,而不会跨越两个段的分界处。
  • 页式系统地址空间是一维的,即单一的线性地址空间,程序员只需利用一个标识符,即可表示一个地址。分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。
  • 段比页大,因而段表比页表短,可以缩短查找时间,提高访问速度。

2. 虚拟内存

产生背景:

对于进程来说,直接操作物理地址,会有如下问题:

  • 数据覆盖:同一个物理地址,可能a,b进程都在使用,a写的数据,有可能被b覆盖
  • 数据重复:对不同进程来说,可能存在相同的数据,存在同一份数据多处存储的现象
  • 难以连续存放:程序往往需要占用连续内存,而这需要实时地对现有的逻辑地址空间进行判断和协调,也容易造成浪费
  • 内存空间不统一:需要人为指定所占用的逻辑地址空间,不同程序的需求不一样
    以上难点的原因是直接操作物理地址的方式太重。

解决方案:

在物理地址空间上包一层虚拟地址空间。试想一下,如果只有一个进程,那么上面的问题是不是就不存在了。虚拟内存的作用,就是屏蔽底层物理内存的操作细节,让每个进程感受不到其他进程的存在
具体细节:
每个进程都分配相同的虚拟内存空间,如都为4GB。进程数据通过虚拟内存,映射到当前可用的物理内存。这样每个程序拥有自己独立的虚拟地址空间,不存在数据覆盖的问题,因为操作系统在建立虚拟内存到物理内存的映射时,会避免各个进程在物理内存上的互相干扰。
虽然在虚拟内存空间里,进程的数据是连续存放的,但映射后的物理内存却不必连续,可充分利用碎片资源。对于多个进程公用的数据,在物理内存中可以只存一份,不同进程使用时只需建立到该物理内存的映射即可,降低了数据的重复。

问题:

假设现在物理内存为4GB,两个进程a,b的虚拟内存都是4GB,虚拟内存之和大于实际物理内存的容量,那会不会放不下?
答案是,当然会放不下。放不下怎么办?放磁盘里!
因此实际运行时的步骤如下:

  • 装载程序时,只将当前指令所需的部分页面放入内存,其余放在磁盘
  • 运行时发现所需指令或数据不在内存中:缺页中断,CPU通知操作系统从磁盘中将相应页面或段加载到内存
  • 从磁盘调入页面到内存发现内存不够用:页面置换,即将当前内存中不用的页放到磁盘中,将需要的页放进来
    这样,虚拟内存就用有限的内存满足了超过实际物理内存容量的需求

虚拟页表

那虚拟内存是这么映射到物理内存的呢?答案是虚拟页表,有MMU(内存管理单元)维护。每个进程维护一个单独的虚拟页表,通过虚拟地址,找到虚拟页表中存放的物理地址,再通过该物理地址,找到存储在内存中的数据。因此,虚拟页表中的页有三种状态:

  • 未映射的页:虚拟页的值为nil
  • 已映射外存:但外存的数据还没有缓存到内存中
  • 已映射内存:即外存数据已经缓存到内存中
    虚拟地址为16位,由页号+页内偏移构成
  • 页号:4位,前3位为索引,最后一位表示是否在内存中,1代表在内存中,0表示不在
  • 页内偏移:12位,与页中存储的物理页号组合,构成物理地址。这意味着,某个页的最大偏移量为2的12次方,即页的大小为4KB
举例:

下图为MMU的内部转换过程,输入为16位虚拟地址,输出为16为物理地址。MMU中包含一个页表,表中每个页表项为4位,最后一位表示是否在内存中。图例中,虚拟地址的前四位为0010,即对应页表中索引为2的页表项,其内容为1101。首先检验最后一位是否为1,发现为1,说明数据已经在内存中。取页表项的前三位110,与虚拟地址的后12位,构成物理地址输出,即110 0000 0000 0100。
假设最后一位为0,即数据不在内存中时,MMU会产生缺页中断,将数据调入内存,然后更新页表,然后在重新执行,此时数据已经在内存中,缓存命中。
在这里插入图片描述

快表与分级页表

为加快虚拟地址到物理地址的转换速度,引入了快表的概念。快表相当于页表的缓存,细节如下:

  1. 根据虚拟地址中的页号查快表;
  2. 如果该页在快表中,直接从快表中读取相应的物理地址;
  3. 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
  4. 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页
    内存资源宝贵,页表可能会比较大,因此引入多级页表。
举例:

假如虚拟地址空间为32位(即4GB)、每个页面映射4KB的物理空间,每条页表项大小为4B,则进程需要1M个页表项(4GB / 4KB = 1M),即页表(每个进程都有一个页表)占用4MB(1M * 4B = 4MB)的内存空间。

假如我们使用二级页表,还是上述条件,但一级页表映射4MB的物理空间、二级页表映射4KB的物理空间,则需要1K个一级页表项(4GB / 4MB = 1K)、每个一级页表项对应1K个二级页表项(4MB / 4KB = 1K),这样页表占用4.004MB((1K + 1K * 1K )* 4B = 4.004MB)的内存空间

但在实际运行时,程序可能并不会用到那么多,因此有些一级页表下面没有二级页表。如1-100分成5份,分别是1-20,21-40,41-60,61-80,81-100,但只用到了1-40之间的部分,那么对后面3份一级页表,就不需要设置二级页表。这样页表就得到了精简。

那程序没使用的内存空间不映射不就行了?这样不也减少页表数量吗?

页表承担的职责是将虚拟地址翻译成物理地址。假如虚拟地址在页表中找不到对应的页表项,操作系统就不能工作了,因此页表一定要覆盖全部虚拟地址空间。

另外,二级页表也可以放到磁盘中,在需要的时候调入内存,这又大大减少了内存中的页表数量。

当然,分级页表的代价是时间,多级查询和磁盘置换都会造成耗时,因此这是一种典型的时空权衡。

页面置换算法

当从磁盘调入数据到内存时,可能内存已经满了。这时候需要将当前内存中的数据放到磁盘中(注意并不少删掉),从而给所需数据腾位置。这就是为什么称为置换。本质是希望降低缺页率
一个萝卜一个坑,该淘汰谁呢?最理想的当然是最没用的,换句话说,就是接下来最长时间不会使用的。这是理想情况,显然无法预知。但下面给出的几个算法,都是从这个角度考虑得到

  • 最近最少使用:LRU(Least Recently Used) 换掉最近最不常用的页,因为之前用的少,之后大概率也用的少。
    • 实现:在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高
  • 最近未使用:NRU(Not Recently Used) 每个页面都有两个状态位:R 与 M,当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1。其中 R 位会定时被清零。可以将页面分成以下四类。优先淘汰编号小的,这个顺序大家可以稍微思考一下合理性
    • R=0,M=0
    • R=0,M=1
    • R=1,M=0
    • R=1,M=1
  • 先进先出 : 页面用链表按先后依次连接,每次淘汰内存中最老的页面,即链表的第一个元素
  • 第二次机会算法:仅靠时间显然太粗糙,毕竟有时候”老当益壮“。当页面被访问时,设置该页面的 R 位为 1。替换时,检查最老页面的 R 位。如果 R 位是 0,可以立刻置换掉;如果是 1,就将 R 位清 0,并将其移动到链表尾。相当于再给一次机会。
  • 时钟算法:第二次机会算法需要在链表中移动页面,效率很低。可以将所有页面围城一个环,维护指向最老页面的指针即可。如下图,指针顺时针移动。当前C如果给第二次机会,只需将指针指向D即可,C自动称为链表中的最后一位。

参考文献:

我和面试官之间关于操作系统的一场对弈!写了很久,看完你就可以盘面试官了
CS-Notes:计算机操作系统
记一次腾讯面试:进程之间究竟有哪些通信方式?如何通信?
多级页表如何节约内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值