一、用户态与内核态
1. 什么是用户态和内核态及其区别?
(1)当程序运行在3级特权级上时,就可以称之为运行在用户态,因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;
(2)反之,当程序运行在0级特权级上时,就可以称之为运行在内核态。
(3)虽然用户态下和内核态下工作的程序有很多差别,但最重要的差别就在于特权级的不同,即权力的不同。运行在用户态下的程序不能直接访问操作系统内核数据结构和程序。

2. 用户态切换到内核态的3种方式
(1)系统调用(主动)
这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。
(2)异常(被动)
当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
(3)外围设备的中断(被动)
当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
二、进程与线程
1. 什么是进程和线程?二者有何区别?
(1)进程(Process)是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。
(2)线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
(3)一个进程可以有多个线程,进程在执行过程中拥有独立的内存单元;而线程依赖于进程而存在,多个线程也可以并发执行,但是多个线程共享进程的内存。
2. 进程间的通信有几种方式?
(1)管道(pipe)及命名管道(named pipe):管道一种半双工的通信方式,数据只能单项流动,可用于具有亲缘关系的父子进程间的通信,命名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
(2)信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
(3)消息队列:消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息;
(4)共享内存:可以说这是最有快的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等;
(5)信号量:主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段;
(6)套接字:这是一种更为一般的进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。
3. 进程有哪几种状态以及状态之间的转换?
(1)就绪(Ready)状态:进程已获得除处理机以外的所需资源,等待分配处理机资源;
(2)运行(Running)状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数;
(3)阻塞(Blocked)状态: 进程等待某种条件,在条件满足之前无法执行。

4. 操作系统中进程调度策略有哪几种?
(1)FCFS(先来先服务,队列实现,非抢占的):先请求CPU的进程先分配到CPU。
(2)SJF(最短作业优先调度算法):平均等待时间最短,但难以知道下一个CPU区间长度。
(3)优先级调度算法(可以是抢占的,也可以是非抢占的):优先级越高越先分配到CPU,相同优先级先到先服务,存在的主要问题是:低优先级进程无穷等待CPU,会导致无穷阻塞或饥饿;解决方案:老化。
(4)时间片轮转调度算法(可抢占的):队列中没有进程被分配超过一个时间片的CPU时间,除非它是唯一可运行的进程。如果进程的CPU区间超过了一个时间片,那么该进程就被抢占并放回就绪队列。
(5)多级队列调度算法:将就绪队列分成多个独立的队列,每个队列都有自己的调度算法,队列之间采用固定优先级抢占调度。其中,一个进程根据自身属性被永久地分配到一个队列中。
(6)多级反馈队列调度算法:与多级队列调度算法相比,其允许进程在队列之间移动:若进程使用过多CPU时间,那么它会被转移到更低的优先级队列;在较低优先级队列等待时间过长的进程会被转移到更高优先级队列,以防止饥饿发生。
5. 进程同步机制有哪些?
(1)信号量机制:一个信号量只能置一次初值,以后只能对之进行p操作或v操作。 由此也可以看到,信号量机制必须有公共内存,不能用于分布式操作系统,这是它最大的弱点。
(2)自旋锁:自旋锁是为了保护共享资源提出的一种锁机制。 调用者申请的资源如果被占用,即自旋锁被已经被别的执行单元保持,则调用者一直循环在那里看是否该自旋锁的保持着已经释放了锁,自旋锁是一种比较低级的保护数据结构和代码片段的原始方式,可能会引起以下两个问题:【死锁】和【过多地占用CPU资源】。
(3)管程:信号量机制功能强大,但使用时对信号量的操作分散,而且难以控制,读写和维护都很困难。因此后来又提出了一种集中式同步进程——管程。其基本思想是将共享变量和对它们的操作集中在一个模块中,操作系统或并发程序就由这样的模块构成。这样模块之间联系清晰,便于维护和修改,易于保证正确性。
(4)会合:进程直接进行仙相互作用。
(5)分布式系统:在分布式操作系统中没有公共内存,因此参数全为值参,而且不可为指针。
6. 线程同步的方式有哪些?
(1)互斥量 Synchronized/Lock:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
(2)信号量 Semphare:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量(从而达到调协进程对共享资源访问的目的)。
(3)事件(信号)Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。
三、死锁
1. 什么是死锁?
在两个或者多个并发进程中,如果每个进程持有某种资源而又等待其它进程释放它或它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁。通俗的讲,就是两个或多个进程无限期的阻塞、相互等待的一种状态。
2. 死锁产生的四个必要条件?
(1)互斥:至少有一个资源必须属于非共享模式,即一次只能被一个进程使用;若其他申请使用该资源,那么申请进程必须等到该资源被释放为止;
(2)占有并等待:一个进程必须占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有;
(3)非抢占:进程不能被抢占,即资源只能被进程在完成任务后自愿释放;
(4)循环等待:若干进程之间形成一种头尾相接的环形等待资源关系。
3. 解决死锁的基本策略和常用方法。
(1)预防死锁:确保死锁发生的四个必要条件中至少有一个不成立,从而预防死锁的发生。
(2)避免死锁:动态地检测资源分配状态,以确保循环等待条件不成立,从而确保系统处于安全状态。资源分配图算法和银行家算法是两种经典的死锁避免的算法。
(3)检测死锁:为每个进程和每个资源指定一个唯一的号码,然后建立资源分配表和进程等待表。
(4)解除死锁:常用两种方法为进程终止和资源抢占。
四、内存管理
1. 分段和分页有什么区别?
分段和分页其实都是一种对地址的划分或者映射的方式,两者的区别主要有以下几点:
(1)目的不同:分页是由于系统管理的需要而不是用户的需要,它是信息的物理单位;分段的目的是为了能更好地满足用户的需要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;
(2)大小不同:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;
(3)地址空间不同: 段向用户提供二维地址空间;页向用户提供的是一维地址空间;
(4)信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制;
(5)内存碎片**:页式存储管理的优点是没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满);而段式管理的优点是没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)。
2. 什么是虚拟内存?
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率。

3. 物理地址、虚拟地址(线性地址)、逻辑地址的知识
(1)物理地址,CPU地址总线传来的地址,由硬件电路控制(现在这些硬件是可编程的了)其具体含义。物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存、BIOS等)。在没有使用虚拟存储器的机器上,虚拟地址被直接送到内存总线上,使具有相同地址的物理存储器被读写;而在使用了虚拟存储器的情况下,虚拟地址不是被直接送到内存地址总线上,而是送到存储器管理单元MMU,把虚拟地址映射为物理地址。
(2)线性地址(Linear Address)也叫虚拟地址(virtual address)是逻辑地址到物理地址变换之间的中间层。在分段部件中逻辑地址是段中的偏移地址,然后加上基地址就是线性地址。是一个32位无符号整数,可以用来表示高达4GB的地址,也就是,高达4294967296个内存单元。线性地址通常用十六进制数字表示,值得范围从0x00000000到0xfffffff)程序代码会产生逻辑地址,通过逻辑地址变换就可以生成一个线性地址。如果启用了分页机制,那么线性地址可以再经过变换以产生一个物理地址。如果没有启用分页机制,那么线性地址直接就是物理地址。
(3)逻辑地址是在有地址变换功能的计算机中,访内指令给出的地址 (操作数) 叫逻辑地址,也叫相对地址,也就是是机器语言指令中,用来指定一个操作数或是一条指令的地址。要经过寻址方式的计算或变换才得到内存储器中的实际有效地址即物理地址。一个逻辑地址由两部份组成,段标识符: 段内偏移量。段标识符是由一个16位长的字段组成,称为段选择符。其中前13位是个索引号,后面3位包含一些硬件细节 。
4. 常用的页面置换算法?
(1)FIFO先进先出算法:在操作系统中经常被用到,比如作业调度(主要实现简单,很容易想到);
(2)LRU(Least recently use)最近最少使用算法:根据使用时间到现在的长短来判断;
(3)LFU(Least frequently use)最少使用次数算法:根据使用次数来判断;
(4)OPT(Optimal replacement)最优置换算法:理论的最优,理论就是要保证置换出去的是不再被使用的页,或者是在实际内存中最晚使用的算法。
五、缓冲区溢出
1. 什么是缓冲区溢出?有什么危害?其原因是什么?
(1)缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。
(2)危害有以下两点:
a. 程序崩溃,导致拒绝额服务;
b. 跳转并且执行一段恶意代码。
(3)造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入。


虚拟
陈粒