操作系统面试考点复习(持续更新)

738 阅读9分钟

虚拟内存

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

虚拟内存就是将操作系统的物理内存扩充为更大的逻辑内存,使得应用程序能够使用足够大的内存,虚拟内存使用部分加载的技术,只将应用程序的数据或资源部分加载进内存中,这样内存空间就能够有更多的空间去加载别的应用程序,甚至还能够加载比内存更大的进程,这样看起来内存好像变大了,但是其实这部分内存包含了磁盘或者硬盘,并且叫做虚拟内存。

局部性原理:
1、时间局部性:如果程序中的某条指令被执行,它在不久后可能还会再次执行;如果某数据被访问过,过段时间后可能再次会被访问。

2、空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问。

内存管理机制

简单来说,可以分为连续分配管理非连续分配管理这两种方式。

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

1、段式管理
将内存分为几个固定大小的块,然后每次给应用程序分配一个块的空间,这样当程序运行只需要很小的空间的时候,会造成空间的一个浪费。产生了内存碎片。

2、页式管理
将内存分为相等的且固定的一页一页的形式,这些页比块小的多,划分力度更大,提高了内存利用率,较少了内存碎片。⻚式管理通过⻚表对应逻辑地址和物理地址。

3、段式管理
页式管理中的页是没有实际意义的,段式管理将主存分为一段段的,这些段又比页小得多,并且这些段是由实际的意义的,比如主程序段main、数据段D等等。段式管理通过段表对应逻辑地址和物理地址。

4、段页式管理
先将主存分为了一段段的,然后又将每个段又分为了一页页的,也就是说段⻚式管理机制中段与段之间以及段的内部的都是离散的。

死锁

定义:若系统中存在一组进程(两个或多个),这些进程都占有资源但是同时又在等待其他线程所占有的资源,这种等待永远不会结束,所以就说产生了“死锁”。

产生的原因可以归结为:由于多个进程竞争资源时,进程推进顺序的不当

死锁的必要条件:

  • 互斥:进程应当互斥使用的资源,也就是说一个资源只能由一个进程锁所持有。
  • 占有且等待条件:一个进程请求不到资源而等待时,不会释放自己持有的资源。
  • 不剥夺条件:进程之间不能相互抢夺已经被占有的资源。
  • 循环等待条件:进程之间相互等待资源,形成循环等待链。

如何解决死锁?

  • 鸵鸟策略:直接不管。
  • 死锁预防:破坏死锁的四个必要条件来预防死锁。
  • 死锁避免:通过仔细分配资源来避免死锁。
  • 死锁检测和恢复:检测死锁并作出恢复,发生死锁就采用行动去恢复。

fork函数

在Linux中,fork函数是用来在已存在的进程中创建一个子进程的,而原进程称为父进程。

调用fork函数,当控制转移到内核中的fork代码时,内核会开始做

  • 分配新的内存块和内核数据给子进程,
  • 将父进程的部分数据结构内容拷贝给子进程。
  • 将子进程添加进系统进程表
  • fork返回两次,向父进程返回子进程的pid,向子进程返回0

fork调用失败的原因

  • 系统中有太多进程了
  • 实际用户的进程数超过了线程

进程的状态

运行就绪阻塞

(1)运行(running)态:进程占有处理器正在运行。
(2)就绪(ready)态:进程具备运行条件,等待系统分配处理器以便运行。
(3)等待(wait)态:又称为阻塞(blocked)态或睡眠(sleep)态,指进程不具备运行条件,正在等待某个 事件的完成。

通常,一个进程在创建后将处于就绪状态。每个进程在执行过程中,任意时刻当且仅当处于上述三种状态之一。同时,在一个进程执行过程中,它的状态将会发生改变。引起进程状态转换的具体原因如下:
(1)运行态一一等待态:等待使用资源或某事件发生,如等待外设传输;等待人工干预。
(2)等待态一一就绪态:资源得到满足或某事件己经发生,如外设传输结束;人工干预完成。
(3)运行态一一就绪态:运行时间片到,或出现有更高优先权进程。
(4)就绪态一一运行态:CPU空闲时被调度选中一个就绪进程执行。

进程和线程之间的区别

  1. 根本区别:进程是资源分配的基本单位;线程是进程调度的基本单位。
  2. 开销方面:每个进程拥有自己的代码和数据空间(程序上下文),程序之间的切换开销比较大;线程没有独立的内存空间,同一类线程共享代码和数据空间,每个线程拥有自己的程序计数器和运行栈,线程之间切换开销比较小。
  3. 内存分配方面:系统会给进程分配独立的空间;不会给线程分配独立的空间(线程所使用的资源为所在进程的资源),线程组之间只能共享内存。
  4. 通信方面:线程之间通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行。
  5. 安全方面:多进程比较安全,一个进程崩溃不会导致其它线程崩溃;一个线程崩溃,所处的进程就崩溃(因为共享地址空间)

进程之间的通信方式

1、管道(匿名管道):只存在于内存中的文件,用于具有亲缘关系的父子进程和兄弟进程之间的通信。

2、有名管道:为了克服匿名管道的缺点。提出了有名管道,有名管道严格遵循先进先出。它是以磁盘文件的形式存在的。它可以支持本机任意两个进程之间的通信。

3、消息队列:消息队列是消息的链表,它有特定格式,存放在内存中并且由消息队列标识符标识。跟管道和有名管道不同的是,消息队列是存在内核中的,只有当内核重启或者显性的去删除一个消息队列的时候,它才会被删除。消息队列可以实现消息的随机查询,并且可以按照消息的类型进行读取,比FIFO更有优势。消息队列客服了信号承载信号量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。

4、信号:信号的通信比较复杂,它主要是用于通知接收进程某个事件的发生。

5、信号量:信号量其实就是一个整型的计数器,它主要用于实现进程间的互斥和同步。

6、共享内存:多个进程能够访问同一块内存空间,并且不同进程对共享内存的数据更新都是可见的。(需要依靠某种同步操作,如上面的信号量,互斥锁)

7、socket(套接字):主要用于客户端和服务端之间的网络通信。套接字是支持TCP/IP的网络通信的基本单元,可以看做是不同主机之间进程进行双向通信的端点。(通信双方的一种约定)

线程之间的通信

1、互斥量:只有拥有互斥对象的线程才能够有访问公共资源的权限。(比如Java中的synchronized和lock就是这种机制)。

2、信号量:允许多个线程访问同一个资源,但是需要控制同一时刻访问该资源的一个最大线程数。(Java中的 Semaphore类)

3、事件:wait、notify/notifyAll。通过事件去操作线程的同步。

僵尸进程和孤儿进程

僵尸进程
当进程exit()退出后,它的父进程没有wait()系统调用回收它的进程描述符的信息,导致该进程还遗留在系统的进程表中,占用了内核资源,这样的进程就是僵尸进程。

孤儿进程
当进程还在执行的时候,它的父进程突然退出,此时该进程就是一个孤儿进程。作为一个进程,必须要有一个父进程,否则在它退出之后没人去回收它的进程描述符的信息,浪费资源。所以孤儿进程得找一个父进程,如果所在的进程组没人收养的话,则会被init()进程所收养。