本文档记录了常见的操作系统面试问题,特地记录下来用于临时抱佛脚。
1. 什么是死锁
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
2. 死锁的产生条件
- 互斥:一个资源一次只能被一个进程占用;
- 请求与保持:一个进程请求资源不被允许时,也不会放弃已占有的资源;
- 不可占用:资源不可被抢占;
- 循环等待:进程之间形成头尾相连的互相等待情况。
3. 死锁解除的方法
- 预防死锁 -- 针对死锁产生的四种条件
- 将独享资源变为共享资源
- 一次性把所有所需资源分配给某个进程
- 资源可抢占
- 给资源编号,只能按序取用
- 避免死锁 -- 银行家算法
银行家算法:事先计算,如果将资源按一定顺序分配给某个进程后,能够使进程结束,释放资源(不会产生死锁),则分配;否则不分配
- 检测死锁
- 解除死锁
4. 互斥锁,自旋锁,读写锁,悲观锁,乐观锁 详情参考
-
乐观锁 Vs 悲观锁
- 乐观锁认为,多个线程共享资源时很少会更改共享资源,所以先分配,工作完成后再看资源是否被更改,如果被更改则放弃此次操作;
- 悲观锁认为,线程会更改共享资源,所以每次只能让一个线程占用资源。
-
互斥锁 Vs 自旋锁
- 互斥锁认为,当A占用资源,B想要访问资源时,加锁失败,此时B会释放CPU,进行 线程的上下文切换 (时间开销大)
- 自旋锁认为,当A占用资源,B想要访问资源时,加锁失败,B不会释放CPU,而是进入 忙等待,不用切换上下文
-
读写锁:在执行“读”操作时,可以多个线程共享资源;当执行“写”操作时,将只能允许一个线程访问资源
1. 堆和栈
-
栈是由编译器自动分配和释放,存放函数的参数和局部变量的值,它的访问速度较快。栈上数据的释放是随着出栈自动销毁了。栈的生长方向向下,内存地址由高到低。
-
堆是程序运行时显式申请和释放的内存空间,程序结束后由操作系统回收,容易产生内存碎片。堆的空间比较灵活,可以不连续,通常比栈要大。堆的生长方向向上,内存地址由低到高。
2. 块、页、段、段页式内存
- 块式存储:将内存分成多个块,每次有数据要调入,直接分给它一整个块,管理简单,但空间利用率极低;
- 页式存储:将内存分为多个页,页<块,通过页表查询;
- 段式存储:将内存分为多个段,段<<块,虽然更加细粒度,但是一段数据可能要分布在多个段上,非常费尽;
- 段页式存储:先将内存分为多个段,再在段的基础上划分多个页。此时每查询一个数据要访问三次内存。
3. 虚拟内存
用于扩充内存的。 它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
1. 进程 Vs 线程
从根本上来说,进程是操作系统分配资源的基本单位,线程是操作系统任务调度的基本单位。
- 进程的切换需要涉及到资源的调动,非常低效,但是转换线程不需要涉及资源调动,效率高;
- 进程内可以有多个线程,这些线程共享进程的资源;而各个进程间又是相互独立的;
- 进程崩溃,不会对其他线程有害;线程崩溃,整个进程都要完蛋,所以会影响其他线程;
2. 信号量与PV操作
信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于 进程间同步。为了获得共享资源,进程需要执行下列操作:
(1)创建一个信号量:这要求调用者指定初始值,对于二值信号量来说,它通常是1,也可是0;
(2)等待一个信号量:该操作会测试这个信号量的值,如果小于0,就阻塞。也称为P操作;
(3)挂出一个信号量:该操作将信号量的值加1,也称为V操作。
- 互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。信号量通常为0/1。
- 同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。
3. 进程调度
- 非抢占:一个任务在处理时,只有等待其完成,才能进行下一步,用于批处理
- 抢占:一个任务在处理时,其他进程可能可以打断其执行
- FIFO
- 最短作业优先 -- 会造成饥饿(即一个进程可能长时间得不到资源)
- 时间片轮转
- 优先级 -- 会造成饥饿
- 最高响应比 -- 响应比=响应事件/处理时间 (即越快能处理完+等了很久的可以先执行)
4. 用户态和内核态
- 用户态的程序只能访问用户空间的资源,执行非特权指令,对于特权指令要通过系统调用的方式进行。
用户态就是提供应用程序运行的空间,为了使应用程序访问到内核管理的资源例如CPU,内存,I/O。内核必须提供一组通用的访问接口,这些接口就叫系统调用
- 运行在内核态的进程控制着操作系统内核程序和计算机的硬件资源,可以执行特权指令和非特权指令。
5. 用户态→内核态
- 系统调用:本身就是中断,只不过是软中断
- 异常
- 硬件中断
6. 进程的状态
进程有三种状态:就绪、执行、阻塞
就绪态是“完事具备,只欠CPU”,阻塞态是除了CPU以外还缺其他资源
7. 上下文切换
上下文切换就是将当前执行的任务转换到下一个任务的过程。在该过程中,还需要保存上一个任务的状态。
进程的上下文切换会涉及内存资源的调度,而线程的上下文切换不会改变内存资源。
8. 并发 & 并行
并行:多个进程在多个处理器上同时执行,在宏观和微观上都是同时执行的;
并发:一个处理器一次只能处理一个进程,即在微观上,是串行的;但是由于进程切换迅速,在宏观上看,一个处理器同时处理多个进程,即并行的。
9. 进程通信
- 管道(Pipe)
- 半双工
- 缓冲区类似于循环队列,空间有限
- 管道是没有ID标识的(针对匿名管道,后面推出有名管道FIFO后解决该问题)
- 保存在内存中
- 消息队列
- 类似于链表构成的队列
- 有特定标识符
- 保存在内核中
- 信号量(semaphore)
- PV操作
- 共享内存
- socket
- 可以让不在同一台计算机但通过网络连接计算机上的进程进行通信
- 套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
- 信号(Signal)
- 中断系统就是使用信号机制,由某个进程发出,在到达接收方前阻塞,直到接收方可以接受为止,接收方接受后,保护断点和上下文,进行转换