---
description: 全是从面经里扒拉出来的面试题
---

# 常见问题

## 进程和线程

**进程：资源分配的基本单位**，一个进程中可以有多个线程，它们共享进程资源，线程不拥有资源，线程可以访问隶属进程的资源。

**线程：独立调度的基本单位**，在同一进程中，线程的切换不会引起进程切换。

* 系统开销 由于创建或撤销进程时，系统都要为之分配或回收资源，如**内存空间、I/O 设备**等，所付出的开销远大于创建或撤销线程时的开销。
  * 类似地，在进行进程切换时，涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置。
  * 而线程切换时只需保存和设置少量寄存器内容，开销很小。
* 通信方面 线程间可以通过直接读写同一进程中的数据进行通信，但是**进程通信需要借助 IPC**。
* [为什么有进程还要线程](https://blog.csdn.net/N1314N/article/details/93711245)：减少程序在并发执行时所付出的时空开销，提高并发性。

## **进程间通信**

> 类似问题：
>
> * 操作系统中有哪些跨进程通信（IPC）的方法

[📌进程通信](../basic/process#jin-cheng-tong-xin)

进程通信的**六**种方式：**管道、FIFO、消息队列、信号量、共享存储、套接字。**

**管道：**&#x901F;度慢，容量有限，只有父子进程能通讯。管道是一种半双工的通信方式，数据只能单向流动，而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

**FIFO：**&#x4EFB;何进程间都能通讯，但速度慢。FIFO是一种半双工的通信方式，但是它允许无亲缘关系进程间的通信。

**消息队列：**&#x5BB9;量受到系统限制，且要注意第一次读的时候，要考虑上一次没有读完数据的问题。消息队列是由消息的链表，存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

**信号量：**&#x4E0D;能传递复杂消息，只能用来同步。信号量是一个计数器，可以用来控制多个进程对共享资源的访问。它常作为一种锁机制，防止某进程正在访问共享资源时，其他进程也访问该资源。因此，主要作为进程间以及同一进程内不同线程之间的同步手&#x6BB5;**。**

**共享内存区：**&#x80FD;够很容易控制容量，速度快，但要保持同步，比如一个进程在写的时候，另一个进程要注意读写的问题，相当于线程中的**线程安全**，当然，共享内存区同样可以用作线程间通讯，不过没这个必要，线程间本来就已经共享了同一进程内的一块内存。

共享内存就是映射一段能被其他进程所访问的内存，这段共享内存由一个进程创建，但多个进程都可以访问。共享内存是最快的 IPC 方式，它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制，如信号量，配合使用，来实现进程间的同步和通信。

**套接字Socket：**&#x5957;接口也是一种进程间通信机制，与其他通信机制不同的是，它可用于不同机器间的进程通信。

**消息队列对比管道、FIFO的优点：**

* 消息队列可以独立于读写进程存在，从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难；
* 避免了 FIFO 的同步阻塞问题，不需要进程自己提供同步方法；
* 读进程可以根据消息类型有选择地接收消息，而不像 FIFO 那样只能默认地接收。

## 进程同步

[📌进程同步](../basic/process#jin-cheng-tong-bu)

* 进程同步：控制多个进程按一定顺序执行
* 进程通信：进程间传输信息

## **线程通信**

方式一：使用 volatile 关键字。使用共享内存的思想，大致意思就是多个线程同时监听一个变量，当这个变量发生变化的时候 ，线程能够感知并执行相应的业务。这也是最简单的一种实现方式。

方式二：使用 Object 类的wait()、notify() 和 notifyaAlL()，它们是多线程通信的基础，而这种实现方式的思想自然是线程间通信。

注意：wait() 和 notify() 必须配合 synchronized 使用。

> 调用 wait() 使得线程等待某个条件满足，线程在等待时会被挂起，当其他线程的运行使得这个条件满足时，其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。它们都属于 Object 的一部分，而不属于 Thread。只能用在同步方法或者同步控制块中使用，否则会在运行时抛出IllegalMonitorStateException。使用 wait() 挂起期间，线程会释放锁。这是因为，如果没有释放锁，那么其它线程就无法进入对象的同步方法或者同步控制块中，那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程，造成死锁。

## **线程安全**

> Java

保证线程安全可从多线程三特性出发：

**原子性（Atomicity）**：单个或多个操作是要么全部执行，要么都不执行

* Lock：保证同时只有一个线程能拿到锁，并执行申请锁和释放锁的代码
* synchronized：对线程加独占锁，被它修饰的类/方法/变量只允许一个线程访问

原子性就是说一个操作不可以被中途cpu暂停然后调&#x5EA6;**，**&#x5373;不能被中断，要不就执行完，要不就不执行。如果一个操作是原子性的，那么在多线程环境下，就不会出现变量被修改等奇怪的问题。

**可见性（Visibility）**：当一个线程修改了共享变量的值，其他线程能够立即得知这个修改

* volatile：保证新值能立即同步到主内存，且每次使用前立即从主内存刷新；
* synchronized：在释放锁之前会将工作内存新值更新到主存中

**有序性（Ordering）**：程序代码按照指令顺序执行

* volatile： 本身就包含了禁止指令重排序的语义
* synchronized：保证一个变量在同一个时刻只允许一条线程对其进行lock操作，使得持有同一个锁的两个同步块只能串行地进入

## 一定有线程吗？为什么要有线程？

> 类似问题：
>
> * 操作系统一定有线程吗？
> * 为什么要有线程

[请你说一说有了进程，为什么还要有线程？](https://blog.csdn.net/N1314N/article/details/93711245)

## 谈谈对操作系统中的**进程**的理解

## 线程和进程的**同步机制和通信机制**

## 进程的内存布局，哪些是线程共享

## 进程与线程的切换开销

## 进程同步

## 进程调度算法

## 进程调度的策略，现在的OS主要是什么策略

## 进程内部和进程之间如何处理同一个文件

## 线程调度的方式

## 什么是缓存溢出

## **并发和并行分别是什么意思**，多线程是并发还是并行

## 单CPU能实现多任务并行吗

## CPU 调度算法

> 类似问题：
>
> * CPU 调度算法，多核的情况下，操作系统怎么处理

## 为什么有多进程也有多线程

> 扯到了虚拟内存空间，面试官就问为什么要这样设计？解决什么问题？

## 操作系统的内存管理

> 分页分段段页式

## 虚拟内存和物理内存的区别

## 假如手机只有10M内存，**想要申请1M的内存是否一定成功**

## 内存分布

## 什么是虚拟内存、共享内存、物理内存

## 虚拟内存的作用

## 说说共享内存的原理

## 分页分段管理

## 分段和分页有什么区别

## 页一般多大

## 中断

> 类似问题：
>
> * 中断是什么，Linux的中断命令
> * 中断是怎么实现的
> * linux 崩溃中断
> * 解释一下中断

## 操作系统有哪些算法支持高效的内存的申请与释放，同时最大化的减少碎片

zero-copy 与 copy-on-write(COW);

## 地址空间的概念

## 指针能不能访问0x0

## 如何在进程中直接操作物理地址

## 计算机寻址的方式

## 直接寻址和间接寻址谁更安全

## 为什么要分用户态、内核态

> 类似问题：
>
> * 用户态/内核态
> * 内核态、用户态相关，扯了几句异常控制流

## 时间片

> 4个CPU，16个数，每个CPU每次只能比较一次两个数的大小，只能返回`true`或`false`，互相之间不能通信，一轮以时间片为单位，需要几轮能够找出最大的数（4个CPU与4个数，可以一轮就找到最大的数吗）

## 死锁以及如何避免死锁

> 类似问题：
>
> * 死锁的四个条件，开发过程中什么情况容易造成死锁

## 多线程访问堆段会出现什么问题，如何解决这些问题

> (信号量、锁)

## 堆和栈的区别

## 生产者-消费者模型，其中的同步机制是怎么样的

## 读者写者模型

> 类似问题：
>
> * 读者-写者问题

## 什么是抢占

## 程序崩溃

> 多线程会不会导致程序崩溃，程序会因为什么崩溃，子线程崩了的话进程会不会崩？(如果捕获了异常或信号就不会崩)

## 什么情况下会stackoverflow

## 操作系统的锁底层如何实现

## 知道哪些锁，说说它们的区别

## 什么是互斥锁/读写锁

> 类似问题：
>
> * 什么场景用互斥锁，什么场景用读写锁

## 文件I/O的过程

## 什么是写优先和读写平衡

## 大小端
