【面试题】操作系统面试题整理——具身智能 / 自动驾驶 / 嵌入式 / 后台开发通用

目录

  • 操作系统高频面试题
  • 一、基础概念(送分题)
    • [1. 什么是操作系统?OS 的核心功能有哪些?](#1. 什么是操作系统?OS 的核心功能有哪些?)
    • [2. 内核态 vs 用户态区别?为什么要区分?](#2. 内核态 vs 用户态区别?为什么要区分?)
    • [3. 系统调用是什么?和普通函数调用区别?](#3. 系统调用是什么?和普通函数调用区别?)
    • [4. 并发 vs 并行区别?](#4. 并发 vs 并行区别?)
    • [5. 同步 vs 异步区别?](#5. 同步 vs 异步区别?)
    • [6. 阻塞 vs 非阻塞区别?](#6. 阻塞 vs 非阻塞区别?)
    • [7. 什么是中断?硬中断 / 软中断 / 异常区别?](#7. 什么是中断?硬中断 / 软中断 / 异常区别?)
    • [8. 什么是上下文切换?开销在哪里?](#8. 什么是上下文切换?开销在哪里?)
    • [9. 什么是虚拟内存?为什么需要?](#9. 什么是虚拟内存?为什么需要?)
    • [10. 什么是抖动(thrashing)?如何避免?](#10. 什么是抖动(thrashing)?如何避免?)
  • 二、进程与线程(最高频,机器人必问)
    • [1. 进程是什么?线程是什么?](#1. 进程是什么?线程是什么?)
    • [2. 进程 vs 线程区别(重点:资源、切换开销、共享、通信)](#2. 进程 vs 线程区别(重点:资源、切换开销、共享、通信))
    • [3. 进程有哪些状态?状态转换图?](#3. 进程有哪些状态?状态转换图?)
    • [4. PCB 是什么?里面存什么?](#4. PCB 是什么?里面存什么?)
    • [5. 进程创建:fork() 做了什么?写时复制(COW)?](#5. 进程创建:fork() 做了什么?写时复制(COW)?)
    • [6. 孤儿进程、僵尸进程、守护进程分别是什么?](#6. 孤儿进程、僵尸进程、守护进程分别是什么?)
    • [7. 僵尸进程危害?如何避免?](#7. 僵尸进程危害?如何避免?)
    • [8. 线程实现方式:用户级线程 vs 内核级线程](#8. 线程实现方式:用户级线程 vs 内核级线程)
    • [9. 多线程优缺点?](#9. 多线程优缺点?)
    • [10. 什么是协程?协程 vs 线程区别?](#10. 什么是协程?协程 vs 线程区别?)
    • [11. 进程通信方式(IPC)有哪些?各自优缺点、适用场景?](#11. 进程通信方式(IPC)有哪些?各自优缺点、适用场景?)
    • [12. 线程同步方式有哪些?](#12. 线程同步方式有哪些?)
    • [13. 死锁四个必要条件?死锁处理策略?](#13. 死锁四个必要条件?死锁处理策略?)
    • [14. 银行家算法是什么?](#14. 银行家算法是什么?)
    • [15. 什么是竞态条件(race condition)?](#15. 什么是竞态条件(race condition)?)
  • 三、调度算法(必考)
    • [1. 常见调度算法有哪些?](#1. 常见调度算法有哪些?)
    • [2. 各算法优缺点、适用场景?](#2. 各算法优缺点、适用场景?)
    • [3. 周转时间、响应时间、带权周转时间计算?](#3. 周转时间、响应时间、带权周转时间计算?)
    • [4. IO 密集型 vs CPU 密集型进程调度策略区别?](#4. IO 密集型 vs CPU 密集型进程调度策略区别?)
    • [5. 什么是抢占式调度?非抢占式?](#5. 什么是抢占式调度?非抢占式?)
  • 四、内存管理(机器人/嵌入式非常高频)
    • [1. 逻辑地址 vs 物理地址?](#1. 逻辑地址 vs 物理地址?)
    • [2. 分页、分段、段页式区别?](#2. 分页、分段、段页式区别?)
    • [3. 页表、快表 TLB 作用?](#3. 页表、快表 TLB 作用?)
    • [4. 缺页中断处理流程?](#4. 缺页中断处理流程?)
    • [5. 页面置换算法](#5. 页面置换算法)
    • [6. 内部碎片 vs 外部碎片?](#6. 内部碎片 vs 外部碎片?)
    • [7. 堆和栈的区别?](#7. 堆和栈的区别?)
    • [8. 内存泄漏是什么?如何排查?](#8. 内存泄漏是什么?如何排查?)
    • [9. 野指针、悬空指针是什么?](#9. 野指针、悬空指针是什么?)
    • [10. mmap 原理与用途?](#10. mmap 原理与用途?)
  • 五、文件系统(高频)
    • [1. 文件系统功能?](#1. 文件系统功能?)
    • [2. 索引节点 inode 是什么?存什么?](#2. 索引节点 inode 是什么?存什么?)
    • [3. 软链接 vs 硬链接区别?](#3. 软链接 vs 硬链接区别?)
    • [4. 虚拟文件系统 VFS 作用?](#4. 虚拟文件系统 VFS 作用?)
    • [5. 磁盘调度算法](#5. 磁盘调度算法)
    • [6. 什么是日志文件系统?ext4 /xfs 特点?](#6. 什么是日志文件系统?ext4 /xfs 特点?)
    • [7. 打开文件过程(fd、inode、dentry 关系)](#7. 打开文件过程(fd、inode、dentry 关系))
  • [六、IO 管理(机器人、自动驾驶、后端都爱问)](#六、IO 管理(机器人、自动驾驶、后端都爱问))
    • [1. IO 模型](#1. IO 模型)
    • [2. select / poll / epoll 区别?为什么 epoll 高性能?](#2. select / poll / epoll 区别?为什么 epoll 高性能?)
    • [3. 水平触发 vs 边缘触发?](#3. 水平触发 vs 边缘触发?)
    • [4. 零拷贝原理?sendfile、mmap?](#4. 零拷贝原理?sendfile、mmap?)
    • [5. DMA 作用?](#5. DMA 作用?)
    • [6. 块设备 vs 字符设备?](#6. 块设备 vs 字符设备?)
  • [七、Linux 系统相关(机器人开发几乎必问)](#七、Linux 系统相关(机器人开发几乎必问))
    • [1. ps、top、htop、free、df、du、netstat、ss、lsof、dmesg 作用](#1. ps、top、htop、free、df、du、netstat、ss、lsof、dmesg 作用)
    • [2. 如何查看进程占用内存 / CPU?](#2. 如何查看进程占用内存 / CPU?)
    • [3. 如何查看端口占用?](#3. 如何查看端口占用?)
    • [4. 如何排查高 CPU / 高内存 / 负载高问题?](#4. 如何排查高 CPU / 高内存 / 负载高问题?)
      • 高CPU
      • 高内存
      • [负载高(load average 高)](#负载高(load average 高))
    • [5. 什么是页缓存(page cache)?](#5. 什么是页缓存(page cache)?)
    • [6. buffer 和 cache 区别?](#6. buffer 和 cache 区别?)
    • [7. 软中断、上下文切换高怎么看?](#7. 软中断、上下文切换高怎么看?)
    • [8. 什么是 OOM killer?触发条件?](#8. 什么是 OOM killer?触发条件?)
  • 八、锁与同步(机器人多线程控制必问)
    • [1. 互斥锁、自旋锁、读写锁适用场景?](#1. 互斥锁、自旋锁、读写锁适用场景?)
    • [2. 自旋锁为什么适合短临界区?](#2. 自旋锁为什么适合短临界区?)
    • [3. 条件变量为什么要配合锁使用?](#3. 条件变量为什么要配合锁使用?)
    • [4. 什么是可重入锁?](#4. 什么是可重入锁?)
    • [5. 公平锁 vs 非公平锁?](#5. 公平锁 vs 非公平锁?)
    • [6. 如何实现一个生产者消费者模型?](#6. 如何实现一个生产者消费者模型?)
    • [7. 读者写者问题、哲学家就餐问题解法?](#7. 读者写者问题、哲学家就餐问题解法?)
  • [九、嵌入式 / 机器人方向特化高频题](#九、嵌入式 / 机器人方向特化高频题)
    • [1. 实时操作系统(RTOS)是什么?](#1. 实时操作系统(RTOS)是什么?)
    • [2. RTOS vs Linux 区别?](#2. RTOS vs Linux 区别?)
    • [3. 硬实时 vs 软实时?](#3. 硬实时 vs 软实时?)
    • [4. 优先级反转是什么?如何解决?](#4. 优先级反转是什么?如何解决?)
    • [5. 任务调度、定时器、消息队列在 RTOS 中的使用](#5. 任务调度、定时器、消息队列在 RTOS 中的使用)
    • [6. 内存池 vs malloc 优缺点?](#6. 内存池 vs malloc 优缺点?)
    • [7. 中断上下文为什么不能睡眠、不能用 mutex?](#7. 中断上下文为什么不能睡眠、不能用 mutex?)
    • [8. 什么是临界区?如何保护?](#8. 什么是临界区?如何保护?)
    • [9. 设备驱动基本模型?](#9. 设备驱动基本模型?)
    • [10. 如何保证机器人控制线程低延迟?](#10. 如何保证机器人控制线程低延迟?)

操作系统高频面试题

一、基础概念(送分题)

1. 什么是操作系统?OS 的核心功能有哪些?

操作系统是硬件和应用程序之间的"管家",比如 Windows、Linux。

核心功能:

  • 管理 CPU:调度进程/线程,决定谁运行、运行多久
  • 管理内存:分配、回收、隔离地址空间
  • 管理 I/O 设备:键盘、鼠标、磁盘、网卡等统一调度
  • 管理文件系统:存储、读取、权限控制
  • 为上层应用提供运行环境与接口,避免直接操作硬件

2. 内核态 vs 用户态区别?为什么要区分?

  • 用户态:应用程序运行的状态,权限低,不能直接操作硬件和敏感内存。
  • 内核态:操作系统核心运行的状态,权限最高,可以控制所有硬件、访问所有内存。

区分目的:做权限隔离,防止应用程序误操作/恶意操作导致系统崩溃,保证系统稳定和安全。

3. 系统调用是什么?和普通函数调用区别?

应用程序在用户态想做"权限操作"(如读写文件、创建进程、网络通信),不能自己做,必须向操作系统发起请求,这个请求就是系统调用。

区别:

  • 普通函数:在用户态内部调用,开销小。
  • 系统调用:需要切换到内核态,有状态切换开销,是应用与内核的交互入口。

4. 并发 vs 并行区别?

  • 并发:单核 CPU 上多个任务交替执行,看起来同时运行,实际是"来回切换"。
  • 并行:多核 CPU 上多个任务真正同时执行。

一句话:并发是交替做,并行是一起做。

5. 同步 vs 异步区别?

  • 同步:发起操作后必须等待结果完成,才能继续做下一步。
  • 异步:发起操作后不用等,先去做别的事,等完成后系统再通知。

例子:同步排队等餐;异步点单后去逛街,好了再叫你。

6. 阻塞 vs 非阻塞区别?

描述调用时线程的状态:

  • 阻塞:调用没返回前,线程卡住不动,一直等。
  • 非阻塞:调用没就绪就先返回,线程可以去做别的,之后再查询。

同步异步关注"结果怎么返回",阻塞非阻塞关注"等待时干不干活"。

7. 什么是中断?硬中断 / 软中断 / 异常区别?

中断就是 CPU 正在执行任务,被打断去处理更紧急的事情。

  • 硬中断:硬件触发,如键盘按下、网卡收到数据包。
  • 软中断:软件模拟,如系统调用、内核延迟处理任务。
  • 异常:程序自身出错,如除零、非法指令、内存缺页。

8. 什么是上下文切换?开销在哪里?

CPU 从一个进程/线程切换到另一个时,需要保存当前运行信息,再加载下一个的信息,这个过程叫上下文切换。

开销:

  • 保存和恢复寄存器、页表、栈信息
  • CPU 缓存失效,需要重新加载数据
    切换过于频繁会导致系统变慢、CPU 利用率下降。

9. 什么是虚拟内存?为什么需要?

虚拟内存是操作系统给每个进程"虚构"的一大片连续地址空间,让进程以为自己独占内存,实际由操作系统映射到物理内存或磁盘。

作用:

  • 进程地址空间隔离,互不干扰
  • 可以使用比物理内存更大的空间
  • 减少内存碎片,方便内存管理

10. 什么是抖动(thrashing)?如何避免?

内存不足时,进程频繁发生缺页中断,刚换入的内存页马上又被换出,CPU 大部分时间都在换页而不是执行业务,这就是抖动。

避免方法:

  • 减少同时运行的进程数量
  • 增加物理内存
  • 优化程序内存占用
  • 合理调整页面置换策略

二、进程与线程(最高频,机器人必问)

1. 进程是什么?线程是什么?

  • 进程:就是一个跑起来的程序,是操作系统分配资源(内存、文件等)的基本单位。每个进程都有自己独立的地盘,互不干扰。
  • 线程:是进程内部的执行流,是 CPU 真正调度和执行的最小单位。一个进程里可以有多个线程,它们共用进程的资源。

一句话:进程是资源单位,线程是执行单位。

2. 进程 vs 线程区别(重点:资源、切换开销、共享、通信)

  • 资源:进程有独立的地址空间,完全独立;线程共享所属进程的内存和资源。
  • 切换开销:进程切换开销很大;线程切换很轻量,更快。
  • 共享:进程之间默认不共享;线程之间直接共享全局变量、堆等。
  • 通信:进程通信麻烦,要用 IPC 机制;线程直接读写共享数据就行。
  • 稳定性:一个进程挂了不影响别的;一个线程挂了,整个进程可能一起崩。

3. 进程有哪些状态?状态转换图?

主要记 5 个状态:新建、就绪、运行、阻塞(等待)、终止。

关键转换:

  • 就绪 → 运行:被调度器选中,拿到 CPU
  • 运行 → 就绪:时间片用完,或者被更高优先级抢占
  • 运行 → 阻塞:需要等 IO、锁、信号,主动让出 CPU
  • 阻塞 → 就绪:等待的事情完成了,重新排队等 CPU

面试说清楚这四条转换就够了。

4. PCB 是什么?里面存什么?

PCB 就是进程控制块,相当于操作系统给每个进程建的"档案卡",用来管理进程。

里面主要存:

  • 进程 ID、进程状态
  • 程序计数器(下一步执行哪行)
  • 寄存器上下文(切换时要保存)
  • 内存地址空间信息
  • 打开的文件、信号信息、优先级等

5. 进程创建:fork() 做了什么?写时复制(COW)?

fork() 用来创建一个子进程,几乎把父进程复制一份:

  • 子进程有独立的 PCB
  • 代码、数据、堆栈逻辑上都复制了

但真正内存不直接全复制,用 写时复制 COW

  • 刚开始父子进程共享同一块物理内存,只读
  • 一旦谁要修改数据,才真正复制那一页内存,各自独立
    目的:节省内存 + 让 fork 更快

6. 孤儿进程、僵尸进程、守护进程分别是什么?

  • 孤儿进程:父进程先退出了,子进程还在跑,被 init/systemd 收养,正常运行。
  • 僵尸进程:子进程已经运行结束,但父进程没有来回收它的 PCB,进程表里还占着位置。
  • 守护进程:后台长期运行的进程,不依赖终端,系统服务一般都是守护进程。

7. 僵尸进程危害?如何避免?

危害:

僵尸进程只占 PCB 不占内存,但数量多了会占满进程表,导致系统无法创建新进程。

避免方法:

  • 父进程用 wait() / waitpid() 主动回收子进程
  • 注册信号处理函数,处理 SIGCHLD 信号
  • 父进程先退出,让子进程变成孤儿,由系统回收

8. 线程实现方式:用户级线程 vs 内核级线程

  • 用户级线程:由线程库在用户态管理,内核不知道它存在。切换很快,但一个线程阻塞会导致整个进程阻塞,不能利用多核。
  • 内核级线程:由操作系统内核管理、调度。可以多核并行,更稳定,但切换开销稍大。
    现在 Linux 上基本都是内核级线程。

9. 多线程优缺点?

优点:

  • 线程切换快、通信方便
  • 能充分利用多核 CPU,提高并发效率
  • 程序结构更清晰,把不同任务分开写

缺点:

  • 线程安全问题多,容易出现竞态、死锁
  • 调试难度比单线程大
  • 一个线程异常可能导致整个进程崩溃

10. 什么是协程?协程 vs 线程区别?

协程是用户态自己切换的轻量级执行单元,不由操作系统调度。

对比线程:

  • 线程切换:内核调度,有用户态/内核态切换,开销大
  • 协程切换:完全在用户态,自己决定什么时候让出,开销极小
  • 线程是抢占式调度;协程是协作式调度
  • 高并发场景下,协程能支持远多于线程的数量

11. 进程通信方式(IPC)有哪些?各自优缺点、适用场景?

  1. 管道:简单、单向,只能父子/兄弟进程用,效率一般
  2. 命名管道:不限制亲缘关系,可用于任意进程间通信
  3. 消息队列:按消息收发,独立于进程,简单但容量有限
  4. 共享内存:直接共享内存区域,速度最快,但需要自己做同步
  5. 信号量:主要用于同步、互斥,不适合传大量数据
  6. 信号:简单通知机制,不能传复杂数据
  7. Socket:可跨主机、跨网络,是最通用的进程通信方式

12. 线程同步方式有哪些?

  • 互斥锁(mutex):保证同一时刻只有一个线程进入临界区
  • 自旋锁:不睡眠,循环等待,适合临界区很短的场景
  • 读写锁:读可以共享,写必须独占,适合读多写少
  • 条件变量:等待某个条件满足时再执行,常和互斥锁配合
  • 信号量:控制同时进入临界区的线程数量

13. 死锁四个必要条件?死锁处理策略?

四个必要条件(必须同时满足才会死锁):

  1. 互斥条件:资源同时只能被一个线程占用
  2. 请求并保持:持有资源的同时又申请新资源
  3. 不可剥夺:资源不能被强行抢走
  4. 循环等待:多个线程形成资源等待环

处理策略:

  • 死锁预防:破坏任意一个必要条件
  • 死锁避免:银行家算法,动态判断是否安全
  • 死锁检测与恢复:允许死锁,定期检查,杀掉进程恢复
  • 鸵鸟算法:假装没发生,简单高效,Linux 实际常用

14. 银行家算法是什么?

银行家算法是一种死锁避免算法。

每次进程申请资源时,系统先假设分配,然后检查系统是否还处于安全状态 (存在安全执行序列)。

安全就分配,不安全就拒绝或等待,保证系统不会进入死锁。

15. 什么是竞态条件(race condition)?

多个线程同时读写同一块共享数据,执行顺序不确定,导致最终结果不可预料、每次运行可能不一样,这种情况就是竞态条件。

本质是:多个执行流竞争资源,没有正确同步。

解决:加锁、原子操作、同步机制。


三、调度算法(必考)

1. 常见调度算法有哪些?

面试只需要说这几个最常考的:

  • FCFS 先来先服务
  • SJF 短作业优先 / SRTF 最短剩余时间优先
  • 优先级调度
  • 时间片轮转 RR
  • 多级反馈队列调度

2. 各算法优缺点、适用场景?

  • FCFS:先来先运行,简单但对短作业不友好,容易"长作业堵死短作业"。
  • SJF:短任务优先,平均等待时间最短,但可能导致长任务饥饿,是非抢占式。
  • SRTF:SJF 的抢占版,新短任务来了可以打断长任务,效率更高,但复杂。
  • 优先级调度:按优先级跑,高优先级先运行,可能出现饥饿,可用 aging 解决。
  • 时间片轮转 RR:每个任务轮流跑一个时间片,公平、响应快,适合交互式系统。
  • 多级反馈队列:综合型,分多个队列,时间片逐级变长,兼顾长短任务,Linux 类似思路。

3. 周转时间、响应时间、带权周转时间计算?

  • 周转时间 = 完成时间 - 到达时间(从进来到跑完一共花多久)
  • 等待时间 = 周转时间 - 运行时间(真正在排队等 CPU 的时间)
  • 带权周转时间 = 周转时间 / 运行时间(衡量公平性)
  • 响应时间:从提交到第一次被运行的时间(交互式系统看重)

面试官一般只考公式理解,不会让你现场算复杂题。

4. IO 密集型 vs CPU 密集型进程调度策略区别?

  • CPU 密集型:一直占 CPU 计算,适合给长一点时间片,减少切换开销。
  • IO 密集型:经常等磁盘/网络,运行很短就要阻塞,适合给短时间片,提高响应速度,让它快速用完 CPU 去等 IO。

5. 什么是抢占式调度?非抢占式?

  • 非抢占式:进程拿到 CPU 就一直跑完,或主动放弃才切换,简单但不实时。
  • 抢占式:操作系统可以强行把 CPU 抢走,给更高优先级任务,实时性好,适合机器人、嵌入式这种需要及时响应的场景。

四、内存管理(机器人/嵌入式非常高频)

1. 逻辑地址 vs 物理地址?

  • 逻辑地址:程序里用的地址,是虚拟的,每个进程都从 0 开始,互相看不见。
  • 物理地址:真实硬件内存的地址,真正存在内存条上的位置。
    操作系统负责把逻辑地址翻译成物理地址。

2. 分页、分段、段页式区别?

  • 分页:把内存切成等大小的页,地址连续、物理上可以不连续,管理简单。
  • 分段:按程序逻辑分(代码段、数据段、栈段),符合人类逻辑,但容易产生外部碎片。
  • 段页式:先分段,再在段内分页,结合两者优点,Linux 实际使用类似思路。

3. 页表、快表 TLB 作用?

  • 页表:存"逻辑页号 → 物理页号"的映射表,查页表才能访问内存。
  • TLB 快表:专门放最常用的页表条目,硬件缓存,查一次很快。
    不命中 TLB 才去查内存里的页表,提高地址翻译速度。

4. 缺页中断处理流程?

  1. CPU 访问一页,发现不在内存中,触发缺页中断。
  2. 操作系统挂起当前进程。
  3. 从磁盘把这一页读到内存。
  4. 如果内存满了,先置换掉某一页。
  5. 更新页表,重新执行刚才的指令。

5. 页面置换算法

常考 4 个:

  • FIFO:先进先出,简单但可能出现刚进来就被换掉。
  • LRU:最近最少使用,把最久没用的页换掉,效果好、面试最爱。
  • OPT:理想算法,换掉未来最远才用的,实际做不到,只用来对比。
  • Clock 时钟算法:近似 LRU,简单高效,Linux 内核常用。

6. 内部碎片 vs 外部碎片?

  • 内部碎片:分配给进程的空间里,没用完的部分,比如给了 4K 只用了 2K。分页容易产生。
  • 外部碎片:总空间够,但分散不连续,没法分配给新进程。分段容易产生。

7. 堆和栈的区别?

  • 栈:函数自动分配,自动释放,速度快,空间小,连续。
  • 堆:手动 malloc/new 申请,手动 free/delete 释放,速度慢,空间大,不连续。
    栈由系统管理;堆需要程序员自己管理。

8. 内存泄漏是什么?如何排查?

内存泄漏:malloc 申请了内存,用完没有 free,一直占着不释放,程序越跑占内存越多。

排查:

  • 看内存占用持续上涨
  • Linux 下用 valgrind、addresssanitizer 检测
  • 检查是否有 malloc 无对应 free

9. 野指针、悬空指针是什么?

  • 悬空指针:指针指向的内存已经被释放了,但指针没置空,还在乱指。
  • 野指针:指针没有初始化,指向随机地址,直接用会崩溃。
    共同点:都会导致非法访问内存,程序崩溃。

10. mmap 原理与用途?

把文件直接映射到进程的虚拟地址空间,读文件就像读内存一样。

优点:

  • 减少拷贝,实现零拷贝
  • 读写大文件方便
  • 可用于进程间共享内存
    用途:读大文件、共享内存、数据库、高性能 IO。

五、文件系统(高频)

1. 文件系统功能?

文件系统就是操作系统用来管理硬盘上文件的一套机制,主要干这些事:

  • 负责文件的创建、删除、读写、重命名
  • 管理文件存在磁盘的哪个位置,怎么存放
  • 管理目录结构,方便查找文件
  • 控制权限:谁能读、谁能写、谁能执行
  • 保证文件数据安全、断电不轻易损坏

一句话:帮系统把杂乱的磁盘空间,整理成能存文件、能找到文件的结构。

2. 索引节点 inode 是什么?存什么?

inode 可以理解成文件的"身份证+档案"

Linux 里每个文件都对应一个 inode,文件名只是方便人看,系统真正认的是 inode。

里面主要存:

  • 文件大小、权限、所有者、时间
  • 文件数据在磁盘上的位置(指向数据块)
  • 文件类型(普通文件/目录/设备等)
  • 链接数(有几个名字指向它)

不存:文件名

3. 软链接 vs 硬链接区别?

  • 硬链接:相当于给文件再起一个别名,和原文件共用同一个 inode。删一个不影响另一个,不能跨分区,不能给目录用。
  • 软链接:相当于快捷方式,存的是原文件路径,有独立 inode。原文件删了就失效,可以跨分区,可以给目录用。

一句话:硬链接是同一个文件;软链接是快捷方式。

4. 虚拟文件系统 VFS 作用?

VFS 是操作系统在上层提供的统一文件界面 ,相当于一个"适配器"。

不管底层是 ext4、xfs、NTFS 还是 U 盘、网络盘,对应用程序都提供一样的 API(open、read、write 等)。

作用:

  • 让上层程序不用关心底层是什么文件系统
  • 统一管理文件、目录、文件描述符等
  • 实现跨文件系统的操作

5. 磁盘调度算法

磁盘调度就是磁头怎么移动找数据更高效,常考这几个:

  • FCFS:先来先服务,简单但磁头乱跑,效率低
  • SSTF:最短寻道优先,找最近的,效率高但可能饥饿
  • SCAN(电梯算法):磁头像电梯一样来回扫,公平高效
  • C-SCAN:只往一个方向扫,到头直接回去,更均匀

面试说清楚:减少磁头移动距离,提高磁盘访问速度即可。

6. 什么是日志文件系统?ext4 /xfs 特点?

日志文件系统:写入前先记日志,断电后能快速恢复,不容易损坏文件结构。

  • ext4:通用、稳定,适合大多数场景,小文件性能不错,使用最广
  • xfs:高并发、大文件、大容量磁盘表现更好,删除大文件超快,适合服务器、数据库

7. 打开文件过程(fd、inode、dentry 关系)

简化版面试回答:

  1. 用文件名找到目录项 dentry(文件名 → inode 的桥梁)
  2. 通过 dentry 找到文件对应的 inode
  3. 内核创建一个文件表项记录打开状态
  4. 给进程返回一个文件描述符 fd(就是一个小数字,用来代表打开的文件)

关系:

  • fd:进程手里的"文件编号"
  • dentry:目录项,管文件名
  • inode:文件本体信息

六、IO 管理(机器人、自动驾驶、后端都爱问)

1. IO 模型

常见 5 种 IO 模型,面试说重点就行:

  1. 阻塞 IO

    调用了就一直等,数据没好就卡住不动,最简单,但并发不行。

  2. 非阻塞 IO

    没数据就立刻返回"没好",不用死等,但需要程序反复去问。

  3. IO 多路复用

    用 select/poll/epoll 同时盯很多个连接,哪个好了处理哪个,高并发核心。

  4. 信号驱动 IO

    先不管,数据好了内核发信号通知,用得少。

  5. 异步 IO

    提交请求后直接干别的,数据完全拷贝好后系统再通知,真正不耽误事。

一句话记:

阻塞=死等;非阻塞=问一下就走;多路复用=同时盯很多;异步=彻底不用管。

2. select / poll / epoll 区别?为什么 epoll 高性能?

区别(大白话版)

  • select:有连接数限制,每次都要把所有 fd 传给内核,遍历找就绪的,效率低。
  • poll:和 select 原理差不多,只是没有最大 fd 限制,但依然要全量遍历,效率还是低。
  • epoll :内核里维护一份 fd 集合,不用每次全量传,只返回真正就绪的,不用遍历。

为什么 epoll 高性能?

  1. 不用每次都重新传所有 fd 给内核
  2. 内核直接返回就绪列表,时间复杂度 O(1)
  3. 支持边缘触发,进一步减少通知次数
  4. 高并发场景下,连接越多 epoll 优势越明显

3. 水平触发 vs 边缘触发?

  • 水平触发 LT(默认)

    只要缓冲区还有数据,就一直通知你。

    像"门铃一直响,直到你开门拿完东西"。

    简单、不容易漏数据。

  • 边缘触发 ET

    只有状态从无到有变化时 才通知一次。

    像"门铃只响一下,你没拿完也不提醒"。

    效率更高,但必须一次性读完数据,否则会等下一次触发。

一句话:

LT 简单安全;ET 高效但要小心处理。

4. 零拷贝原理?sendfile、mmap?

零拷贝是什么?

传统 IO 要在"内核缓冲区 ↔ 用户缓冲区"之间拷贝数据,浪费 CPU。

零拷贝就是尽量减少甚至去掉多余拷贝,让数据直接从内核到设备。

mmap

把文件映射到进程虚拟地址空间,用户态可以直接读,少一次拷贝。

sendfile

数据直接在内核空间从页缓存发到 socket,完全不经过用户态,真正零拷贝。

总结:

零拷贝 = 少拷贝、不拷贝 → 更快、CPU 占用更低。

5. DMA 作用?

DMA 是专门帮 CPU 搬运数据的硬件。

不用 DMA:

CPU 自己一个个字节搬运,啥也干不了。

用 DMA:

CPU 告诉 DMA 搬哪里,DMA 自己搬,搬完通知 CPU,CPU 可以去干别的。

作用:解放 CPU,提高 IO 效率

6. 块设备 vs 字符设备?

  • 块设备

    按块读写,可以随机访问,有缓存。

    比如:硬盘、U 盘、SD 卡。

  • 字符设备

    按字节流读写,顺序访问,一般无缓存。

    比如:键盘、鼠标、串口、传感器、显示器。

一句话:块设备 = 存数据的;字符设备 = 传数据流的。


七、Linux 系统相关(机器人开发几乎必问)

1. ps、top、htop、free、df、du、netstat、ss、lsof、dmesg 作用

  • ps:查看当前进程快照(静态列表)
  • top:实时查看进程 CPU、内存、系统负载
  • htop:top 的升级版,界面更友好,支持鼠标操作
  • free:查看内存使用情况(总内存、已用、空闲、缓存)
  • df:查看磁盘分区使用情况(磁盘还剩多少空间)
  • du:查看文件/目录占用了多少磁盘空间
  • netstat:查看网络连接、端口、路由表(老工具)
  • ss:比 netstat 更快的网络连接查看工具
  • lsof:列出当前打开的文件(也能查端口、进程打开的文件)
  • dmesg:查看内核日志(硬件、驱动、系统启动报错)

2. 如何查看进程占用内存 / CPU?

  • top:直接看,按 CPU 排序按 P,按内存排序按 M
  • ps aux:静态列出所有进程的 CPU、内存占用
  • htop:更直观,实时排序查看
  • pidstat:专门看进程 CPU/内存 统计

3. 如何查看端口占用?

  • lsof -i:端口号
  • netstat -tulnp | grep 端口号
  • ss -tulnp | grep 端口号

4. 如何排查高 CPU / 高内存 / 负载高问题?

高CPU

  1. top 看哪个进程 CPU 高
  2. 用 top -H -p 进程ID 看是哪个线程占 CPU
  3. 用 strace 看系统调用,或看程序逻辑死循环、计算密集

高内存

  1. top 看内存占用高的进程
  2. 看是否持续上涨,判断内存泄漏
  3. 使用 valgrind、asan 排查泄漏点

负载高(load average 高)

  1. 可能是 CPU 忙、IO 等待高、锁竞争严重
  2. top 看 %wa(IO等待)是否高
  3. 看磁盘 IO、上下文切换、锁等待

5. 什么是页缓存(page cache)?

Linux 会把最近读过的文件数据缓存在内存里,下次再读直接从内存取,不用读硬盘,这部分缓存就是页缓存。

作用:极大提高文件读取速度。

6. buffer 和 cache 区别?

  • buffer:写给磁盘之前的临时缓冲,用于写数据缓冲
  • cache:从磁盘读出来后缓存起来,用于读数据加速
    简单记:buffer 写给磁盘,cache 读自磁盘。

7. 软中断、上下文切换高怎么看?

  • top 看 %si(软中断 CPU 占比)
  • vmstat 看 cs(上下文切换次数)、in(中断)
  • pidstat -w 看进程上下文切换
  • sar 看系统级切换统计

高切换一般是:线程太多、锁竞争激烈、网络包太多。

8. 什么是 OOM killer?触发条件?

OOM killer 是内核的"保护机制"。

当系统内存严重不足,为了不让系统直接卡死,内核会杀掉占用内存最大的进程来释放内存。

触发条件:

  • 物理内存 + swap 都不够用
  • 无法再分配内存
  • 内核触发 Out Of Memory 机制

八、锁与同步(机器人多线程控制必问)

1. 互斥锁、自旋锁、读写锁适用场景?

  • 互斥锁(mutex)

    最通用,拿不到锁就线程休眠,不占CPU。

    适用:大多数场景,临界区不确定长短、通用业务逻辑。

  • 自旋锁(spinlock)

    拿不到锁就循环忙等,不休眠,一直占CPU。

    适用:多核、临界区极短、内核线程、实时性要求高的场景(机器人控制常用)。

  • 读写锁(rwlock)

    读可以并发,写必须独占。

    适用:读多写少,比如配置读取、数据查询、日志读取。

2. 自旋锁为什么适合短临界区?

自旋锁是"死等不睡觉",一直占着CPU轮询。

如果临界区很长,CPU会白白空转浪费资源。

临界区很短时,等几下就能拿到锁,比"休眠+唤醒"的开销小得多,所以适合短临界区。

3. 条件变量为什么要配合锁使用?

条件变量是用来"等某个条件成立"的,比如队列不空、数据就绪。

  • 线程在检查条件时,必须先加锁,保证条件判断是原子的
  • wait 操作会原子释放锁并进入等待,避免其他线程修改数据造成混乱
  • 被唤醒后,会自动重新获取锁,再去判断条件

如果不加锁,会出现竞态条件,导致逻辑错乱、死锁或永远等不到信号。

4. 什么是可重入锁?

同一个线程,可以多次获取同一把锁,不会自己锁死自己。

比如函数A加锁,里面调用函数B,函数B也加同一把锁。

不可重入锁会直接死锁;

可重入锁内部有计数,同一线程重复加锁只增加计数,解锁时逐层减少。

5. 公平锁 vs 非公平锁?

  • 非公平锁(默认)

    新线程可以直接尝试抢锁,不用排队,效率更高,但可能出现线程饥饿。

  • 公平锁

    严格按等待顺序排队,先到先得,不会饥饿,但性能稍差,需要维护等待队列。

6. 如何实现一个生产者消费者模型?

最简思路(面试说这个就够):

  1. 一个共享队列作为缓冲区
  2. 互斥锁保证队列操作线程安全
  3. 两个条件变量:
    • not_full:队列不满,生产者可以放
    • not_empty:队列不空,消费者可以拿
      流程:
  • 生产者:加锁 → 队列满就等 not_full → 放数据 → 通知 not_empty → 解锁
  • 消费者:加锁 → 队列空就等 not_empty → 取数据 → 通知 not_full → 解锁

7. 读者写者问题、哲学家就餐问题解法?

读者写者问题

  • 读共享、写独占
  • 实现:
    • 读者优先:多个读者可同时读,写者等所有读者结束
    • 写者优先:写者来了,后续读者等待,避免写者饥饿
  • 实际用读写锁直接解决。

哲学家就餐问题

问题:5个哲学家交替思考、吃饭,5根叉子,每人拿左右两根才能吃,容易死锁。

解法:

  1. 最多允许4人同时抢叉子
  2. 偶数号先拿左再拿右,奇数号先拿右再拿左
  3. 一次性申请所有叉子,成功再拿,失败全释放
    核心思路:破坏循环等待条件,避免死锁

九、嵌入式 / 机器人方向特化高频题

1. 实时操作系统(RTOS)是什么?

RTOS 是面向实时控制 的操作系统,核心特点是:响应时间可预测、确定性高、延迟小

它不追求"跑得快",而追求"到点必须执行",主要用于机器人、无人机、工控、汽车电子等。

2. RTOS vs Linux 区别?

  • RTOS:小巧、实时性强、抢占调度严格、功能简单、资源占用极小。
  • Linux:功能强大、生态完善、支持多核大内存,但实时性差、抖动大、延迟不可控。

一句话:
Linux 适合做"大脑"处理复杂逻辑;RTOS 适合做"手脚"做实时控制。

3. 硬实时 vs 软实时?

  • 硬实时:超时就是事故,必须严格按时完成,比如机器人电机控制、汽车刹车。
  • 软实时:偶尔慢一点没事,比如视频播放、网络传输。

机器人控制基本都是硬实时要求。

4. 优先级反转是什么?如何解决?

场景:

高优先级任务等低优先级任务持有的锁,而低优先级又被中优先级抢占,导致高优先级被"卡住"。

解决方法:

  • 优先级继承:低优先级任务临时"借"高优先级,防止被中间任务抢占。
  • 优先级天花板:只要持有锁,优先级直接升到最高。

5. 任务调度、定时器、消息队列在 RTOS 中的使用

  • 任务调度:按优先级抢占式调度,高优先级任务可以立刻打断低优先级。
  • 定时器:用于周期控制,比如电机 1ms 控制一次、传感器 5ms 读一次。
  • 消息队列:任务之间安全传递数据,解耦、线程安全,是 RTOS 最常用通信方式。

6. 内存池 vs malloc 优缺点?

  • malloc:灵活,但容易产生碎片,分配时间不确定,实时系统禁止用
  • 内存池:预先分配好固定大小块,分配释放时间固定、无碎片、稳定可控。

机器人/RTOS 里基本都用内存池,不用 malloc。

7. 中断上下文为什么不能睡眠、不能用 mutex?

  • 中断是抢占执行的,不属于任何任务,没有"调度"可言,一睡眠系统直接崩溃。
  • mutex 可能导致阻塞、等待,而中断里不能阻塞、不能调度
    中断里只能用自旋锁、信号量这类不睡眠的同步方式。

8. 什么是临界区?如何保护?

临界区:多个线程/中断会同时访问的共享代码或数据区域。

保护方式:

  • 关中断(最快、极短临界区)
  • 自旋锁
  • 互斥锁(任务间)
    原则:临界区越短越好。

9. 设备驱动基本模型?

简化版:

  1. 硬件初始化(时钟、引脚、寄存器)
  2. 提供统一接口:open / read / write / ioctl
  3. 中断处理函数
  4. 数据读写与控制逻辑
    上层不用关心硬件细节,只调用统一接口。

10. 如何保证机器人控制线程低延迟?

  • 设为最高优先级,禁止被其他任务抢占
  • 使用 RTOS 或 Linux 实时内核(PREEMPT_RT)
  • 控制线程逻辑简单,避免 IO、打印、复杂计算
  • 避免锁竞争、长时间阻塞
  • 关闭不必要的中断、减少上下文切换
  • 周期固定,避免抖动
相关推荐
海寻山3 小时前
Java内部类:4种类型+实战场景+面试避坑
java·开发语言·面试
蓝色的杯子4 小时前
Python面试30分钟突击掌握-LeetCode3-Linked list
python·leetcode·面试
RePeaT4 小时前
React 常用知识点整理
前端·react.js·面试
何陋轩4 小时前
Elasticsearch搜索引擎深度解析:把搜索核心讲透,面试都是小菜
后端·面试
Baihai_IDP4 小时前
以 Nano-vLLM 为例,深入理解 LLM 推理引擎(Part 1)
人工智能·面试·llm
wuxinyan1234 小时前
Java面试题48:一文深入了解java设计模式
java·设计模式·面试
有意义4 小时前
【面试复盘】前端底层原理与 React 核心机制深度梳理
前端·react.js·面试
San304 小时前
深入浅出:彻底搞懂 WebSocket、SSE 与心跳机制
websocket·tcp/ip·面试
橙露5 小时前
后端开发面试:高频项目经验描述模板(可直接背)
面试·职场和发展