1.Linux内核
Linux内核
一、进程调度子系统(Process Scheduler)
1. 核心职责
进程调度子系统是内核的 “CPU 资源分配器”,负责决定哪个进程 / 线程在哪个 CPU 核心上**何时运行 **,核心目标是:
- 公平性:所有进程都能获得合理的 CPU 时间片;
- 高效性:最大化 CPU 利用率,减少进程切换开销;
- 响应性:保证交互式进程(如终端、GUI 程序)的快速响应。
2. 核心概念与机制
(1)进程状态
内核通过 task_struct 结构体的 state 字段描述进程状态,关键状态包括:
| 状态 | 含义 |
|---|---|
TASK_RUNNING |
运行态 / 就绪态:进程正在 CPU 上运行,或在就绪队列等待调度 |
TASK_INTERRUPTIBLE |
可中断睡眠态:进程等待某事件(如 IO 完成、信号),可被信号唤醒 |
TASK_UNINTERRUPTIBLE |
不可中断睡眠态:进程等待硬件事件(如磁盘 IO),不能被信号唤醒,避免硬件操作被打断 |
TASK_ZOMBIE |
僵尸态:进程已终止,但父进程未调用 wait 回收其资源,task_struct 仍存在 |
TASK_STOPPED |
停止态:进程被信号(如 SIGSTOP)暂停执行 |
(2)调度策略
Linux 内核支持多种调度策略,以适配不同类型的进程:
SCHED_NORMAL(默认)
- 面向普通进程(如后台服务、命令行程序),采用 CFS(完全公平调度器) 实现;
- CFS 的核心思想:给每个进程分配比例公平的 CPU 时间,通过 “虚拟运行时间” 计算进程优先级,虚拟运行时间越短的进程,越优先被调度。
SCHED_FIFO
- 实时先进先出调度策略,适用于硬实时进程;
- 高优先级进程一旦就绪,立即抢占低优先级进程;同优先级进程按 “先到先服务” 顺序执行,直到主动放弃 CPU。
SCHED_RR
- 实时时间片轮转调度策略,适用于软实时进程;
- 同优先级进程轮流使用 CPU 时间片(默认 100ms),时间片耗尽后被放回就绪队列尾部。
(3)关键数据结构
- **
task_struct**:进程控制块,存储进程的调度信息(优先级、调度策略、虚拟运行时间等); - **
runqueue**:每个 CPU 核心对应一个就绪队列,存储该核心上的就绪进程,避免多核心竞争; - **
sched_entity**:调度实体,嵌入在task_struct中,描述进程的调度属性(如虚拟运行时间、权重)。
3. 调度流程
- 触发时机:进程时间片耗尽、进程主动放弃 CPU(如
sleep)、高优先级进程就绪; - 选择下一个进程:CFS 遍历就绪队列,选择虚拟运行时间最短的进程;
- 上下文切换:保存当前进程的 CPU 寄存器状态(到
task_struct),恢复目标进程的寄存器状态,完成进程切换。
二、内存管理子系统(Memory Management, MM)
1. 核心职责
内存管理子系统是内核的 “内存资源管理器”,负责物理内存和**虚拟内存 ** 的分配、回收与映射,核心目标是:
- 为每个进程提供独立的虚拟地址空间,避免进程间内存冲突;
- 高效利用物理内存(如通过分页、交换、缓存机制);
- 支持内存共享(如动态库、进程间共享内存)。
2. 核心概念与机制
(1)虚拟地址空间
在 64 位 Linux 系统中,每个进程拥有 128TB 的虚拟地址空间,内核将其划分为两个部分:
- 用户空间(0 ~ 0x7fffffffffff):进程私有,包含代码段、数据段、堆、栈等;
- 内核空间(0xffff880000000000 ~ 末尾):所有进程共享,存放内核代码和数据,用户态进程需通过系统调用访问。
(2)分页机制(核心)
虚拟地址无法直接访问物理内存,内核通过分页机制实现虚拟地址到物理地址的映射:
- 页面大小:默认 4KB(可配置为 2MB/1GB 大页,减少页表开销);
- 多级页表:64 位系统使用 4 级页表(PGD → PUD → PMD → PTE),避免页表占用过多内存;
- MMU 硬件加速:CPU 内置的内存管理单元(MMU)会缓存页表项(TLB),加速地址转换。
(3)物理内存分配机制
内核提供两种核心物理内存分配器,适配不同场景:
伙伴系统(Buddy System)
- 用于分配 大块连续物理内存(以 2 的幂次方为单位,如 4KB、8KB、16KB);
- 核心思想:将物理内存划分为多个块组,分配时寻找大小匹配的块,释放时合并相邻块,减少内存碎片。
Slab 分配器
- 用于分配 小块内存(如内核数据结构
task_struct、file); - 核心思想:为每种数据结构创建一个 “缓存池”,预分配若干个对象,分配 / 释放时直接从缓存池获取 / 归还,避免频繁调用伙伴系统,提升效率。
- 用于分配 小块内存(如内核数据结构
(4)虚拟内存扩展机制
交换分区(Swap)
- 当物理内存不足时,内核将不常用的内存页面写入磁盘交换分区,释放物理内存;
- 当进程再次访问该页面时,内核将其从交换分区读回物理内存(缺页中断)。
内存映射(mmap)
- 将文件 / 设备映射到进程的虚拟地址空间,进程可通过内存操作直接读写文件,无需
read/write系统调用; - 核心优势:减少数据拷贝次数,提升大文件操作效率。
- 将文件 / 设备映射到进程的虚拟地址空间,进程可通过内存操作直接读写文件,无需
3. 关键数据结构
- **
mm_struct**:进程内存描述符,存储进程的虚拟地址空间信息(如页表指针、堆 / 栈起始地址); - **
page**:物理页面描述符,每个物理页面对应一个page结构体,记录页面的状态(如是否被占用、所属进程); - **
vm_area_struct**:虚拟内存区域描述符,描述进程虚拟地址空间中的一个连续区域(如代码段、堆)。
4. 缺页中断处理流程
当进程访问未映射的虚拟地址时,触发缺页中断,内核处理流程:
- 检查虚拟地址是否合法(是否在进程的
vm_area_struct范围内); - 若合法:分配物理页面,建立虚拟地址到物理地址的映射,更新页表;
- 若非法:触发段错误(
SIGSEGV),终止进程。
三、虚拟文件系统子系统(Virtual File System, VFS)
1. 核心职责
虚拟文件系统是内核的 “文件系统抽象层”,它屏蔽了不同物理文件系统(如 ext4、xfs、tmpfs)的差异,为用户态提供**统一的文件操作接口 **(open/read/write/close)。核心目标是:
- 支持多种文件系统的无缝挂载与访问;
- 统一管理所有文件类资源(普通文件、目录、设备文件、套接字)。
2. 核心设计思想
VFS 定义了四个核心抽象对象,所有物理文件系统都需实现这些对象的操作接口,从而接入 VFS 框架:
| 抽象对象 | 作用 | 对应物理文件系统实现 |
|---|---|---|
| 超级块(super_block) | 描述一个已挂载的文件系统的全局信息(如文件系统类型、块大小) | ext4 的 ext4_sb_info |
| 索引节点(inode) | 描述一个文件的元数据(如大小、权限、创建时间),每个文件对应唯一的 inode | ext4 的 ext4_inode_info |
| 目录项(dentry) | 描述文件的路径信息(如文件名、父目录),是路径到 inode 的映射,存在于目录项缓存 | VFS 统一管理,与物理文件系统无关 |
| 文件对象(file) | 描述进程打开的文件的上下文信息(如当前读写位置、打开模式) | 与物理文件系统无关 |
3. 核心机制
(1)目录项缓存(Dentry Cache)
- 内核将常用的目录项(dentry)缓存到内存中,避免每次访问文件都从磁盘读取目录结构;
- 缓存采用 LRU 算法淘汰不常用的目录项,平衡缓存命中率和内存占用。
(2)页缓存(Page Cache)
- 内核将文件数据缓存到物理内存中(以页面为单位),进程读取文件时优先从页缓存获取,未命中时再从磁盘读取;
- 写文件时,数据先写入页缓存,内核通过回写线程异步将脏页面写入磁盘,提升写操作效率。
(3)设备文件(/dev 目录)
VFS 将硬件设备抽象为文件,通过设备驱动实现文件操作接口:
- 字符设备:以字节流方式访问(如串口、键盘),对应
c类型文件; - 块设备:以块为单位访问(如磁盘、U 盘),对应
b类型文件; - 进程通过
read/write操作设备文件,内核会调用对应的设备驱动函数,完成硬件交互。
4. 典型操作流程(以 read 为例)
- 用户态调用
read(fd, buf, len),触发系统调用; - 内核通过进程的
files_struct找到file对象; - 调用
file->f_op->read函数(由具体文件系统实现); - 检查页缓存:若数据在页缓存中,直接拷贝到用户缓冲区;若不在,从磁盘读取数据到页缓存,再拷贝到用户缓冲区;
- 更新
file->f_pos(文件当前读写位置),返回读取的字节数。
四、网络接口子系统(Network Interface, NET)
1. 核心职责
网络接口子系统是内核的 “网络通信管理器”,实现了 TCP/IP 协议栈的核心功能,负责**网络数据包的收发、路由、协议解析 **。核心目标是:
- 为应用程序提供统一的网络编程接口(如 socket 套接字);
- 支持多种网络协议(TCP、UDP、ICMP 等)和网络设备(以太网、无线网卡);
- 实现高效的数据包转发与处理。
2. 核心架构与协议栈
Linux 网络子系统采用分层架构,与 TCP/IP 五层模型对应:
| 协议栈分层 | 内核组件 | 核心功能 |
|---|---|---|
| 应用层 | socket 接口 | 为用户态提供网络编程接口(socket/bind/listen/accept) |
| 传输层 | TCP/UDP 协议模块 | 实现端到端通信(TCP 可靠传输、UDP 无连接传输) |
| 网络层 | IP/ICMP 协议模块 | 实现数据包的路由选择与分片 / 重组 |
| 数据链路层 | 网络设备驱动 / 网桥 | 实现 MAC 地址解析、帧的收发 |
| 物理层 | 硬件网卡 | 负责二进制数据的电信号传输 |
3. 核心机制与数据结构
(1)Socket 套接字
Socket 是网络通信的端点,内核通过 socket 结构体描述一个套接字:
sk:指向sock结构体,存储套接字的核心信息(如协议类型、本地 / 远端地址、接收 / 发送缓冲区);ops:指向套接字操作函数集(socket_ops),不同协议(TCP/UDP)有不同的实现;file:关联到 VFS 的file对象,使套接字可以通过文件描述符操作。
(2)TCP 协议核心机制
- 三次握手与四次挥手:实现 TCP 连接的建立与关闭;
- 滑动窗口:实现流量控制,避免发送方发送速率过快导致接收方缓冲区溢出;
- 拥塞控制:通过慢启动、拥塞避免、快速重传 / 恢复等算法,适应网络拥塞状态;
- 收发缓冲区:内核为每个 TCP 套接字分配接收缓冲区(存储待应用程序读取的数据)和发送缓冲区(存储待网络发送的数据)。
(3)数据包收发流程(以 TCP 接收为例)
网卡收到数据包后,触发硬中断,内核中断处理函数将数据包从网卡缓冲区拷贝到内核内存;
硬中断处理完成后,触发软中断,内核协议栈开始解析数据包:
- 数据链路层:解析 MAC 地址,判断是否为本机数据包;
- 网络层:解析 IP 地址,判断是否为本地数据包或需要转发;
- 传输层:解析 TCP 端口,找到对应的 socket 套接字;
内核将数据包数据写入 socket 的接收缓冲区;
唤醒等待该 socket 数据的进程(如调用
read阻塞的进程);应用程序调用
read读取接收缓冲区的数据。
五、进程间通信子系统(Inter-Process Communication, IPC)
1. 核心职责
进程间通信子系统提供了进程间数据交换与同步的机制,由于进程拥有独立的虚拟地址空间,无法直接访问彼此的内存,因此需要内核提供专门的 IPC 机制。核心目标是:
- 实现进程间的数据传输(如传递字符串、文件描述符);
- 实现进程间的同步与互斥(如锁、信号量)。
2. Linux 核心 IPC 机制
Linux 提供了多种 IPC 机制,适用于不同的应用场景,可分为三大类:
(1)单机 IPC 机制
| IPC 机制 | 核心特点 | 适用场景 |
|---|---|---|
| 管道(Pipe) | 半双工通信,数据单向流动;基于文件系统,生命周期随进程 | 父进程与子进程间的简单通信 |
| 命名管道(FIFO) | 全双工通信,可用于任意进程间通信;以文件形式存在于文件系统 | 无亲缘关系进程间的简单通信 |
| 信号(Signal) | 异步通信,通过信号传递事件(如 SIGINT、SIGTERM);只能传递有限的信号编号 |
进程间的事件通知(如终止进程、暂停进程) |
| 共享内存(Shared Memory) | 最快的 IPC 机制;内核分配一块物理内存,映射到多个进程的虚拟地址空间 | 大量数据的高频传输(如数据库、游戏引擎) |
| 信号量(Semaphore) | 用于进程间的同步与互斥;通过 PV 操作实现对临界资源的保护 | 多进程共享资源时的互斥访问(如共享内存的读写同步) |
| 消息队列(Message Queue) | 基于队列的消息传递;消息有类型和优先级,可实现异步通信 | 进程间的异步消息传递(如服务端与客户端的指令交互) |
(2)网络 IPC 机制
- Socket 套接字:支持跨主机的进程间通信,基于 TCP/UDP 协议;
- 是网络编程的核心接口,既可以用于单机通信(
127.0.0.1回环地址),也可以用于跨网络通信。
(3)特殊 IPC 机制
- 文件描述符传递:通过
unix domain socket(UNIX 域套接字)在进程间传递文件描述符; - 适用于进程间共享打开的文件、套接字等资源。
3. 核心 IPC 机制详解(以共享内存为例)
共享内存是性能最高的 IPC 机制,核心流程:
- 创建共享内存:进程调用
shmget函数,内核分配一块物理内存,返回共享内存标识符shmid; - 映射到进程地址空间:进程调用
shmat函数,将共享内存映射到自己的虚拟地址空间; - 进程间通信:多个进程映射同一块共享内存后,可直接读写该内存区域,无需内核拷贝数据;
- 解除映射与销毁:进程调用
shmdt解除映射;最后一个进程解除映射后,调用shmctl销毁共享内存,释放物理内存。
核心优势:数据无需在进程间拷贝,直接访问物理内存,通信效率极高;
注意事项:需要配合信号量等同步机制,避免多进程同时读写共享内存导致数据竞争。
六、五大子系统的协同工作
Linux 内核的五大子系统并非孤立存在,而是紧密协作,共同支撑应用程序的运行。以一个 “TCP 网络通信” 场景为例,子系统的交互流程:
- 进程调度:用户态进程调用
socket/read系统调用,触发内核态切换;内核调度进程进入睡眠态,直到网络数据到达。 - 网络接口:网卡收到数据包后,内核协议栈解析数据包,将数据写入 socket 接收缓冲区;唤醒睡眠的进程。
- 进程调度:进程被唤醒,重新进入就绪队列,等待 CPU 调度执行。
- 内存管理:进程调用
read读取接收缓冲区数据时,内核将内核态缓冲区的数据拷贝到用户态缓冲区(涉及虚拟地址到物理地址的映射)。 - 虚拟文件系统:socket 作为特殊的文件对象,通过 VFS 的
file结构体管理,进程通过文件描述符操作 socket。 - 进程间通信:若进程需要将接收到的数据传递给另一个进程,可通过共享内存、消息队列等 IPC 机制实现。