Linux常见问题与分析

发布于:2025-03-15 ⋅ 阅读:(12) ⋅ 点赞:(0)

操作系统进行线程切换时进行的动作

1. 保存当前线程的上下文

  • 寄存器状态:保存 CPU 寄存器(如通用寄存器、程序计数器 PC、栈指针 SP 等)到当前线程的 线程控制块(TCB) 中。
  • 内核栈信息:如果线程在内核态运行(例如因系统调用或中断进入内核),需保存内核栈指针。
  • 浮点 / 向量寄存器:若线程使用了浮点运算或 SIMD 指令,需保存相关寄存器状态。

2. 更新线程状态与调度队列

  • 将当前线程状态从 运行态(Running) 改为 就绪态(Ready)(例如时间片耗尽)或 阻塞态(Blocked)(例如等待 I/O)。
  • 将其 TCB 移动到对应的调度队列(如就绪队列、阻塞队列)。

3. 调度器选择下一个线程

  • 调度器根据算法(如时间片轮转、优先级)从 就绪队列 中选择一个线程,分配 CPU 使用权。

4. 恢复新线程的上下文

  • 从新线程的 TCB 中加载其保存的寄存器状态(包括 PC、SP),恢复 CPU 执行环境。
  • 切换内核栈(如果是内核级线程)。

5. 切换内存地址空间(可选)

  • 同一进程内的线程切换:无需切换地址空间(共享同一进程的页表)。
  • 跨进程的线程切换(如某些系统允许线程跨进程):需更新 内存管理单元(MMU),切换页表,刷新 TLB。

6. 更新系统状态

  • 更新当前运行线程的指针(例如 Linux 的 current 宏)。
  • 更新 CPU 的统计信息(如线程运行时间、调度次数)。

7. 执行新线程

  • 通过恢复的程序计数器(PC)跳转到新线程的代码位置,继续执行。

触发线程切换的典型场景

  • 主动让出 CPU:线程调用 yield() 或等待锁 / I/O。
  • 时间片耗尽:时钟中断触发调度器介入。
  • 高优先级线程就绪:抢占式调度强制切换。

什么是用户态和内核态

1. 用户态(User Mode)

  • 权限:低权限模式,限制对硬件的直接访问。
  • 执行主体:普通应用程序(如浏览器、文本编辑器)。
  • 关键限制
    • 无法直接操作硬件(如磁盘、网络设备)。
    • 内存访问受限:只能访问进程分配的虚拟内存,无法读写内核空间。
    • 特权指令禁用:如修改页表、关闭中断等指令会被 CPU 拒绝执行。
  • 目的:防止用户程序破坏系统或干扰其他进程。

2. 内核态(Kernel Mode)

  • 权限:最高权限模式,可完全控制硬件和系统资源。
  • 执行主体:操作系统内核(如处理中断、管理进程、驱动硬件)。
  • 核心能力
    • 直接访问硬件:如读写磁盘、配置网络设备。
    • 管理内存:修改页表、分配物理内存。
    • 执行特权指令:如开关中断、修改 CPU 运行模式。
  • 目的:保障操作系统对资源的绝对控制,确保系统安全。

切换时呈现8字型

进程间通信的方式有哪些

操作系统中的进程有几种状态

进程的调度算法

进程和线程的区别

进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位. 

什么是软中断什么是硬中断

硬中断是由外部设备产生的中断信号,具有强制中断、快速响应等特点;软中断是由软件指令触发的中断,具有软件触发、灵活性高、处理机制复杂等特点。

为什么要有虚拟内存

  1. 突破物理内存限制
    当程序需要的内存超过实际物理内存时,系统将暂时不用的数据转移到硬盘的「交换空间」,腾出物理内存供急需的程序使用,避免内存耗尽导致崩溃。

  2. 支持多任务并行
    允许同时运行多个大型程序(如视频剪辑 + 游戏),即使总内存需求远超物理内存,也能通过动态调度保持流畅。

  3. 内存隔离与安全
    每个进程拥有独立的虚拟地址空间,程序 A 和程序 B 使用相同的虚拟地址时,实际映射到不同物理地址,防止数据篡改或越界访问。

  4. 简化开发与兼容性
    程序员无需关注物理内存碎片化问题,虚拟内存提供连续的逻辑地址空间,降低开发复杂度;同时统一内存管理策略,提升跨硬件平台的兼容性。

分段与分页

分段(Segmentation)

定义:将程序的逻辑地址空间按功能划分为不同大小的段(如代码段、数据段、堆栈段等),每个段代表一个逻辑单元,可独立分配和管理。
特点

  1. 逻辑划分:段与程序结构对应(如函数、模块),便于程序开发与保护。
  2. 动态大小:段长度由程序需求决定,灵活但易产生外部碎片。
  3. 二维地址:逻辑地址由段号 + 段内偏移组成(如 段A: 0x100)。

示例
程序被划分为代码段(存放指令)、数据段(存放变量)、堆栈段(函数调用栈),每个段独立加载到内存的不同位置。


分页(Paging)

定义:将逻辑地址空间和物理内存划分为固定大小的页(如 4KB),通过页表映射实现非连续内存分配。
特点

  1. 物理划分:页是固定大小的物理单位(如 4KB),消除外部碎片。
  2. 一维地址:逻辑地址由页号 + 页内偏移组成(如 页3: 0xFF)。
  3. 硬件支持:页表由硬件加速地址转换,但可能产生内部碎片。

示例
程序被切分为多个 4KB 的页,分散存储在物理内存的页框中,操作系统通过页表记录页与页框的映射关系。

分段与分片

1. 分段(Segmentation)—— 传输层(TCP)

定义:TCP 协议将应用层数据分割为适合网络传输的较小单元(称为 TCP 段 / Segment),每个段添加 TCP 头部(含端口号、序列号、校验和等)。
目的

  • 适配网络传输的合理数据大小(避免数据过大导致底层分片)。
  • 实现可靠传输:每个段独立编号,便于确认重传和按序重组。

过程示例
假设应用层发送 3000 字节 的数据,TCP 根据 MSS(最大报文段长度,通常约 1460 字节) 将其分为 3 个段:

  1. 段 1:0~1459 字节(序号 = 0)
  2. 段 2:1460~2919 字节(序号 = 1460)
  3. 段 3:2920~3000 字节(序号 = 2920)

特点

  • 由传输层(TCP)完成,对应用透明。
  • 接收端按序号重组数据,保证顺序。

2. 分片(Fragmentation)—— 网络层(IP)

定义:IP 协议将网络层数据包切割为更小的 IP 分片 / Fragment,以适应底层网络的 MTU(最大传输单元,如以太网 MTU=1500 字节)
触发条件:当数据包大小超过某段链路的 MTU 时,路由器或主机进行分片。
目的

  • 解决不同网络链路 MTU 不一致的问题(如从以太网到 PPPoE 链路)。
  • 分片后的数据包可独立传输,但重组由接收端完成。

分片示例
若 IP 层收到一个 4000 字节 的数据包(IP 头部 20 字节 + 数据 3980 字节),而链路 MTU=1500 字节,则分片为:

  1. 分片 1:20 字节头 + 1480 字节数据(总 1500 字节,标志 MF=1,偏移 = 0)
  2. 分片 2:20 字节头 + 1480 字节数据(MF=1,偏移 = 185)
  3. 分片 3:20 字节头 + 1020 字节数据(MF=0,偏移 = 370)

特点

  • 由网络层(IP)处理,对传输层和应用层透明。
  • 分片可能发生在传输路径中的任何路由器。
  • 重组仅在最终接收端进行,中间设备不重组。
  • 分片会降低网络效率(丢失任一分片需重传整个包)。

cpu的使用率和cpu的负载分别是什么,它们有什么关系

CPU 使用率

定义:CPU 在某一时间段内实际执行任务的时间占比(如 80% 表示 CPU 有 80% 时间在工作)。
核心意义:反映 CPU 的忙碌程度


CPU 负载(Load Average)

定义:系统在单位时间内,正在运行和等待 CPU 资源的平均任务数(如负载为 4 表示平均有 4 个任务需处理)。
核心意义:反映系统的任务队列压力,与 CPU 核心数相关(如 4 核 CPU 负载临界值约 4)。

为什么网络IO会被阻塞(多角度)

什么是reactor

Reactor(反应器模式) 是一种事件驱动的编程模型,核心目的是高效处理高并发 I/O 请求。它通过非阻塞 I/O 多路复用(如 epoll/select)监听多个事件源(如网络连接),当事件触发时自动分发到对应的处理程序(回调函数),实现单线程 / 少量线程管理大量连接

IO模型有哪些

模型 数据准备阶段 数据复制阶段 同步 / 异步 适用场景
阻塞 I/O 阻塞 阻塞 同步 简单客户端
非阻塞 I/O 非阻塞(轮询) 阻塞 同步 低并发 + 实时性要求
I/O 多路复用 阻塞(多路等待) 阻塞 同步 高并发服务(Nginx、Redis)
信号驱动 I/O 非阻塞(信号通知) 阻塞 同步 特殊设备监控
异步 I/O 非阻塞 非阻塞 异步 高性能服务器(需内核支持)

select、poll、epoll 的区别

特性

select

poll

epoll

底层数据结构

fd_set(位图数组)

pollfd(链表)

红黑树 + 就绪链表

最大描述符数量

默认 1024(可修改但效率下降)

无限制(由系统内存限制)

无限制(由系统内存限制)

事件触发模式

水平触发(LT)

水平触发(LT)

支持水平触发(LT)和边缘触发(ET)

内核 - 用户数据拷贝

每次调用需拷贝整个 fd_set

每次调用需拷贝整个 pollfd 数组

通过 mmap 共享内存,仅拷贝就绪事件

时间复杂度

O (n),遍历所有 fd

O (n),遍历所有 fd

O (1),仅处理就绪事件

CFS(linux)

CFS 是 Linux 内核的默认进程调度器,自 2.6.23 版本(2007 年)引入,用于管理普通进程(非实时进程)的 CPU 时间分配。其核心目标是公平性,即让所有进程按优先级和权重公平共享 CPU 资源,避免单个进程长时间独占 CPU。

核心机制
  1. 虚拟运行时间(vruntime)

    • 作用:跟踪每个进程的 “虚拟 CPU 使用时间”,公平性由 vruntime 决定。
    • 计算方式
      • 实际运行时间 × 权重因子(权重由进程的 nice 值决定)。
      • nice 值越小(优先级越高),权重越大,vruntime 增长越慢,进程更易被调度。
    • 调度规则:选择红黑树中 vruntime 最小的进程运行。
  2. 红黑树(Red-Black Tree)

    • 作用:高效管理所有可运行进程,按 vruntime 排序。
    • 优势:插入、删除、查找的时间复杂度为 O(log N),确保高并发下调度效率。
  3. 动态时间片

    • 目标延迟(sched_latency_ns):默认 24ms,保证所有进程在此周期内至少运行一次。
    • 最小粒度(sched_min_granularity_ns):默认 3ms,避免频繁上下文切换。
    • 时间片计算:根据进程数和权重动态调整(如 4 个进程时,每个分到 6ms)。
  4. 优先级与权重

    • nice 值范围:-20(最高优先级)到 +19(最低优先级)。
    • 权重表:内核通过 prio_to_weight 数组将 nice 值映射为权重值(如 nice=0 对应权重 1024)。

阻塞模式和非阻塞模式

  1. 阻塞模式

    • 适用简单场景(如单线程顺序处理),编程简单。
    • 缺点:高并发下效率低(线程因等待 I/O 被挂起)。
  2. 非阻塞模式

    • 必须配合 多路复用(select/epoll 或 轮询 使用,否则频繁检查会浪费 CPU。
    • 边缘触发(ET)模式必须使用非阻塞,否则可能因未读完 / 写完数据导致永久阻塞。
    • 优点:支持高并发,线程不会因 I/O 等待被阻塞。

 

 2. send 发送数据

场景 阻塞模式 非阻塞模式
发送缓冲区有空间 将数据复制到内核缓冲区,返回实际写入的字节数(通常是全部数据)。 同左。
发送缓冲区无空间 线程挂起,直到缓冲区有足够空间。 立即返回 -1,设置 errno=EAGAIN/EWOULDBLOCK;或返回已成功复制的部分字节数。
部分空间可用 等待直到缓冲区剩余空间足够容纳全部数据(可能被中断)。 立即复制尽可能多的数据,返回实际复制的字节数。

 


网站公告

今日签到

点亮在社区的每一天
去签到