mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
4115 字
12 分钟
系列导读
2025-01-18

一、系列简介#

本系列从 Linux 内核的用户可见接口出发,自顶向下剖析现代 Linux 操作系统的核心机制。与姊妹篇「从零开始的操作系统」(自底向上手写引导程序)不同,本系列聚焦于 Linux 内核本身的设计与实现——你每天使用的 Linux 系统背后,进程如何被创建与调度、内存如何被分配与回收、文件如何被组织与缓存、网络包如何穿越内核协议栈……每一章都配有可在你自己的 Linux 系统上验证的实践操作,让你从「会用 Linux」进阶到「理解 Linux」。

与姊妹系列的关系#

  • 「从零开始的操作系统」 = 自底向上,从硬件到内核入口(写引导程序)
  • 「从零剖析 Linux 操作系统」 = 自顶向下,从系统调用到内核机制(读 Linux 源码)
  • 两者互补,可独立阅读;本系列在涉及启动流程时会引用姊妹系列

二、场景驱动阅读路线#

不想按部就班地从第 1 章读到第 20 章?没问题。以下 5 条路线从你日常遇到的真实问题出发,按”你需要什么→内核怎么实现”的顺序串联章节。每条路线可独立阅读,前置依赖已在路线内标注。

路线总览#

flowchart TB subgraph 路线A[" 路线A:我的程序跑起来发生了什么"] A1[Ch1 内核架构] --> A2[Ch2 系统调用] A2 --> A3[Ch3 进程管理] A3 --> A4[Ch7 虚拟内存] A4 --> A5[Ch4 进程调度] A5 --> A6[Ch5 信号与IPC] end subgraph 路线B[" 路线B:为什么容器能隔离"] B1[Ch1 内核架构] --> B2[Ch3 进程管理] B2 --> B3[Ch7 虚拟内存] B3 --> B4[Ch15 Cgroups与Namespaces] B4 --> B5[Ch14 同步机制] B5 --> B6[Ch16 安全机制] end subgraph 路线C[" 路线C:文件读写性能调优"] C1[Ch1 内核架构] --> C2[Ch2 系统调用] C2 --> C3[Ch9 VFS与文件系统] C3 --> C4[Ch8 页缓存与IO] C4 --> C5[Ch10 块设备与IO栈] C5 --> C6[Ch6 物理内存管理] end subgraph 路线D[" 路线D:系统出问题了怎么查"] D1[Ch1 内核架构] --> D2[Ch18 追踪与可观测性] D2 --> D3[Ch6 物理内存管理] D3 --> D4[Ch4 进程调度] D4 --> D5[Ch13 中断与软中断] D5 --> D6[Ch20 综合实战] end subgraph 路线E[" 路线E:网络请求穿越内核的完整旅程"] E1[Ch1 内核架构] --> E2[Ch2 系统调用] E2 --> E3[Ch12 网络协议栈] E3 --> E4[Ch13 中断与软中断] E4 --> E5[Ch8 页缓存与IO] E5 --> E6[Ch14 同步机制] end style 路线A fill:#e3f2fd,stroke:#1565c0 style 路线B fill:#e8f5e9,stroke:#2e7d32 style 路线C fill:#fff3e0,stroke:#e65100 style 路线D fill:#fce4ec,stroke:#c62828 style 路线E fill:#f3e5f5,stroke:#6a1b9a

路线A:我的程序跑起来发生了什么#

场景:你在终端输入 ./my_app 按下回车——Shell 是怎么创建新进程的?程序代码如何被加载到内存?CPU 什么时候开始执行你的 main 函数?进程之间如何通信?

顺序章节为什么读这章
1Ch1 内核架构全景建立”用户态/内核态隔离”的认知——程序的一切操作都必须穿越这道墙
2Ch2 系统调用理解 fork()/execve() 如何从用户态陷入内核态完成进程创建
3Ch3 进程管理核心:task_struct 全貌、fork-COW-exec 完整流程、进程状态机——回答”进程是什么”
4Ch7 虚拟内存与VMA理解 execve() 后如何为进程搭建地址空间、缺页异常如何按需加载代码段
5Ch4 进程调度回答”进程何时获得 CPU”——CFS 如何决定下一个运行的是谁
6Ch5 信号与IPC进程不是孤岛:Ctrl+C 如何终止进程、管道如何串联命令、共享内存如何加速数据传递

路线逻辑:从”程序启动”这一动作出发,先理解进程创建(Ch3),再理解进程的内存布局(Ch7),然后理解进程如何被调度执行(Ch4),最后理解进程间如何交互(Ch5)。


路线B:为什么容器能隔离#

场景:Docker run 一个容器,容器里的进程看不到宿主机其他进程、文件系统被隔离、CPU/内存被限制——内核到底做了什么?容器和虚拟机有什么本质区别?

顺序章节为什么读这章
1Ch1 内核架构全景理解内核空间/用户空间隔离——容器的隔离是”内核对用户空间的二次隔离”
2Ch3 进程管理容器的本质是进程——理解 task_structclone() flags 是 Namespace 的入口
3Ch7 虚拟内存与VMA内存 Namespace 如何让容器拥有独立的地址空间视图
4Ch15 Cgroups与Namespaces核心:7 种 Namespace 的隔离能力、Cgroup v2 控制器的资源限制——容器技术的内核根基
5Ch14 同步机制Cgroup 的资源统计与限制依赖内核同步原语,理解锁机制才能理解 cgroup 的并发安全
6Ch16 安全机制容器逃逸的防线:Capabilities 权限拆分、Seccomp-BPF 系统调用过滤、SELinux 强制访问控制

路线逻辑:先建立”进程是容器的基本单元”的认知(Ch3),再理解内存隔离(Ch7),然后直击核心——Namespace+Cgroup(Ch15),最后理解容器的安全边界(Ch14→Ch16)。


路线C:文件读写性能调优#

场景:数据库写入延迟飙升、日志文件 fsync 太慢、Direct I/O 和 Buffered I/O 该选哪个、io_uring 真的比 epoll 快吗?

顺序章节为什么读这章
1Ch1 内核架构全景理解用户态/内核态切换开销——每次 read/write 都要穿越这道墙
2Ch2 系统调用系统调用开销分析——频繁 I/O 的性能瓶颈可能就在 syscall 本身
3Ch9 VFS与文件系统open()read() 的 VFS 路径——dcache 命中与否直接影响延迟
4Ch8 页缓存与IO核心:Page Cache 命中/未命中的性能天壤之别、脏页写回策略、fsync 语义、Direct I/O、io_uring
5Ch10 块设备与IO栈I/O 请求如何穿越 blk-mq 到达磁盘——I/O 调度器选择(BFQ vs mq-deadline)对延迟的影响
6Ch6 物理内存管理内存紧张时 kswapd 回收 Page Cache 页面——“可用内存不足”是 I/O 性能骤降的常见根因

路线逻辑:从用户态 read()/write() 出发,先理解 VFS 层路径(Ch9),再深入 Page Cache 这一最关键的加速器(Ch8),然后追踪 I/O 到磁盘的完整路径(Ch10),最后理解内存压力如何反噬 I/O 性能(Ch6)。


路线D:系统出问题了怎么查#

场景:凌晨 3 点报警——进程卡在 D 状态、OOM Killer 杀了你的 Java 进程、CPU 使用率 100% 但不知道谁在跑、网络延迟飙升。

顺序章节为什么读这章
1Ch1 内核架构全景/proc/sys 是内核向用户空间暴露信息的窗口——排障的第一手数据源
2Ch18 追踪与可观测性核心:ftrace 追踪函数调用、perf 采样分析热点、eBPF 在内核安全执行自定义探测逻辑
3Ch6 物理内存管理OOM Killer 的触发条件与选择策略——理解 oom_score 才能防止关键进程被杀
4Ch4 进程调度D 状态(TASK_UNINTERRUPTIBLE)进程的成因——等待 I/O 完成时调度器无法抢占
5Ch13 中断与软中断Softirq 和 Workqueue 的延迟处理——网络包处理瓶颈常出现在此处
6Ch20 综合实战8 个真实诊断场景的端到端演练——OOM 分析、D 状态排查、调度延迟、I/O 瓶颈、网络丢包

路线逻辑:先掌握观测工具(Ch18),再理解三大类常见问题的内核机制——内存问题(Ch6)、调度问题(Ch4)、中断/网络问题(Ch13),最后通过实战场景综合运用(Ch20)。


路线E:网络请求穿越内核的完整旅程#

场景:一个 HTTP 请求从网卡到达你的 Web 服务器,再返回响应——数据包如何穿越内核协议栈?epoll 为什么比 select 快?Netfilter 钩子在哪里拦截包?

顺序章节为什么读这章
1Ch1 内核架构全景建立内核子系统全貌——网络协议栈是七大子系统之一
2Ch2 系统调用socket()/connect()/accept() 系统调用——用户态如何向内核发起网络请求
3Ch12 网络协议栈核心:sk_buff 数据包表示、TCP 状态机、NAPI 轮询、Netfilter 5 个钩子点、网络命名空间
4Ch13 中断与软中断网卡中断 → NAPI 轮询 → NET_RX_SOFTIRQ——收包的完整中断处理链路
5Ch8 页缓存与IOSocket buffer 与 Page Cache 的关系——sendfile() 零拷贝如何绕过用户空间
6Ch14 同步机制协议栈中的锁竞争——sk_buff 链表的并发保护、RCU 在路由表查找中的应用

路线逻辑:从用户态 socket API 出发(Ch2),深入协议栈核心(Ch12),理解收包的中断链路(Ch13),再看零拷贝优化(Ch8)和并发保护(Ch14)。


路线交叉参考#

同一章节在不同路线中的关注点不同:

章节路线A 关注点路线B 关注点路线C 关注点路线D 关注点路线E 关注点
Ch1用户态/内核态隔离隔离的层次性syscall 开销/proc /sys 数据源子系统全貌
Ch3fork-COW-execclone() flags 与 Namespace
Ch4CFS 调度决策D 状态成因
Ch6kswapd 回收 Page CacheOOM Killer 策略
Ch7进程地址空间布局内存 Namespace
Ch8Page Cache 核心sendfile 零拷贝
Ch12协议栈核心
Ch13Softirq 瓶颈收包中断链路
Ch14cgroup 并发安全协议栈锁竞争
Ch15核心章节
Ch18核心章节

三、知识导图#

以下导图展示 21 章知识之间的网络关系。与线性目录不同,这里强调跨子系统的连接——一个 fork() 调用同时牵动进程管理、虚拟内存、同步机制三个子系统;一个 Page Cache 同时服务于文件系统和内存管理。

概念关系图#

graph TB subgraph 用户可见层[" 用户可见层 — 你能观察和操作什么"] PROC["进程<br/>ps / top / htop"] FILE["文件<br/>ls / cat / strace"] NET["网络<br/>ss / tcpdump / curl"] CONTAINER["容器<br/>docker / kubectl"] PERF_OBS["性能与故障<br/>perf / bpftrace / dmesg"] BOOT["启动<br/>dmesg / systemd-analyze"] end subgraph 内核机制层[" 内核机制层 — 内核如何实现用户可见的行为"] SYSCALL["系统调用<br/>Ch2"] SCHED["调度器<br/>Ch4"] VMA["虚拟内存<br/>Ch7"] PC["页缓存<br/>Ch8"] VFS["VFS<br/>Ch9"] BLK["块设备层<br/>Ch10"] NETSTACK["协议栈<br/>Ch12"] IRQ["中断机制<br/>Ch13"] SYNC["同步原语<br/>Ch14"] NS_CG["Namespace+Cgroup<br/>Ch15"] SECURITY["安全框架<br/>Ch16"] MODULE["内核模块<br/>Ch17"] TRACE["追踪框架<br/>Ch18"] end subgraph 内核基础层[" 内核基础层 — 一切机制的共同地基"] ARCH["内核架构<br/>Ch1"] PHYMEM["物理内存<br/>Ch6"] DRIVER["设备驱动<br/>Ch11"] SIGNAL_IPC["信号与IPC<br/>Ch5"] TASK["进程管理<br/>Ch3"] BOOTFLOW["启动流程<br/>Ch19"] end %% 用户可见 → 内核机制 PROC --> TASK PROC --> SCHED FILE --> VFS FILE --> PC NET --> NETSTACK CONTAINER --> NS_CG PERF_OBS --> TRACE BOOT --> BOOTFLOW %% 内核机制 → 内核基础 SYSCALL --> ARCH SCHED --> TASK VMA --> PHYMEM PC --> PHYMEM VFS --> PC BLK --> DRIVER NETSTACK --> IRQ IRQ --> PHYMEM SYNC --> SCHED NS_CG --> TASK NS_CG --> SYNC SECURITY --> NS_CG MODULE --> DRIVER MODULE --> IRQ TRACE --> MODULE TRACE --> SYNC %% 跨层关键连接 VMA -.->|"COW fork"| TASK PC -.->|"sendfile"| NETSTACK NS_CG -.->|"内存隔离"| VMA IRQ -.->|"网络收包"| NETSTACK SYNC -.->|"RCU 路由"| NETSTACK BOOTFLOW -.->|"初始化"| ARCH SIGNAL_IPC -.->|"信号投递"| TASK style 用户可见层 fill:#e8eaf6,stroke:#283593 style 内核机制层 fill:#e0f2f1,stroke:#00695c style 内核基础层 fill:#fce4ec,stroke:#880e4f

章节网络关系图#

graph LR Ch0["Ch0 导读"] --> Ch1["Ch1 架构"] Ch1 --> Ch2["Ch2 系统调用"] Ch1 --> Ch19["Ch19 启动"] Ch2 --> Ch3["Ch3 进程管理"] Ch2 --> Ch9["Ch9 VFS"] Ch3 --> Ch4["Ch4 调度"] Ch3 --> Ch5["Ch5 信号IPC"] Ch3 --> Ch12["Ch12 网络"] Ch3 --> Ch15["Ch15 容器"] Ch3 --> Ch16["Ch16 安全"] Ch4 --> Ch14["Ch14 同步"] Ch6["Ch6 物理内存"] --> Ch7["Ch7 虚拟内存"] Ch6 --> Ch13["Ch13 中断"] Ch7 --> Ch8["Ch8 页缓存"] Ch7 -.->|"COW"| Ch3 Ch8 --> Ch9 Ch8 --> Ch12 Ch8 -.->|"sendfile"| Ch12 Ch9 --> Ch10["Ch10 块设备"] Ch10 --> Ch11["Ch11 设备驱动"] Ch11 --> Ch17["Ch17 模块"] Ch13 --> Ch17 Ch13 --> Ch14 Ch13 -.->|"收包"| Ch12 Ch14 --> Ch15 Ch14 -.->|"协议栈锁"| Ch12 Ch14 --> Ch18["Ch18 追踪"] Ch15 --> Ch16 Ch15 -.->|"内存隔离"| Ch7 Ch17 --> Ch18 Ch18 --> Ch20["Ch20 实战"] style Ch0 fill:#bbdefb,stroke:#1565c0 style Ch3 fill:#c8e6c9,stroke:#2e7d32 style Ch6 fill:#fff9c4,stroke:#f9a825 style Ch8 fill:#ffe0b2,stroke:#e65100 style Ch12 fill:#e1bee7,stroke:#6a1b9a style Ch15 fill:#b2dfdb,stroke:#00695c style Ch18 fill:#ffcdd2,stroke:#c62828

知识关联参考表#

按三层模型组织:用户可见层(你日常接触的概念)→ 内核机制层(内核如何实现)→ 内核基础层(共享的基础设施)。同一行的条目之间存在直接的知识依赖或概念映射。

用户可见概念对应章节内核机制对应章节共享基础对应章节
进程创建 (fork/exec)Ch3写时复制 (COW)Ch7物理页帧分配Ch6
进程获得 CPUCh4CFS 调度 / 上下文切换Ch4中断时钟触发调度Ch13
malloc() 分配内存Ch7缺页异常 → 页表映射Ch7伙伴系统 / SlubCh6
read() 读文件Ch9VFS → Page Cache 命中/穿透Ch8, Ch9bio → blk-mq → 磁盘Ch10
write() 写文件Ch8脏页标记 → 延迟写回Ch8kswapd 页面回收Ch6
fsync() 持久化Ch8脏页刷盘 + 磁盘 FUACh8, Ch10块设备 I/O 调度Ch10
网络收发数据Ch12sk_buff + TCP 状态机Ch12网卡中断 → NAPI → SoftirqCh13
epoll 高并发Ch12Socket 等待队列 + 唤醒Ch12调度器唤醒抢占Ch4
Docker 容器隔离Ch157 种 NamespaceCh15clone() flagsCh3
容器资源限制Ch15Cgroup v2 控制器Ch15调度器 cgroup 支持Ch4
容器安全边界Ch16Capabilities + SeccompCh16LSM 框架 + credCh3
perf top 热点分析Ch18perf 采样 + 硬件计数器Ch18内核模块插桩Ch17
bpftrace 动态追踪Ch18eBPF 验证器 + JITCh18内核同步 (RCU)Ch14
OOM Killer 杀进程Ch6内存水位线 + oom_scoreCh6进程凭证 (oom_score_adj)Ch3
进程卡在 D 状态Ch4TASK_UNINTERRUPTIBLECh4I/O 等待 + 块设备队列Ch10
sendfile() 零拷贝Ch8Page Cache → Socket 直传Ch8, Ch12DMA 引擎Ch11
系统启动慢Ch19start_kernel → systemdCh19子系统初始化顺序Ch1
内核模块加载Ch17.ko ELF → 符号解析Ch17设备驱动模型Ch11
Ctrl+C 终止进程Ch5SIGINT 信号投递Ch5进程信号处理Ch3
管道 `` 串联命令Ch5pipe → 内核缓冲区Ch5Page Cache (pipe_buffer)

四、系列大纲#

以下是按章节编号排列的完整目录。建议结合上方的场景驱动阅读路线知识导图选择适合你的阅读顺序。

章节标题核心内容
0系列导读系列定位、场景路线、知识导图、环境搭建
1Linux 内核架构全景用户/内核空间隔离、七大子系统、执行上下文、内核数据结构
2系统调用特权级切换、sys_call_table、VDSO、strace、系统调用开销
3进程管理task_struct、进程状态机、fork-COW-exec、僵尸/孤儿进程
4进程调度CFS、vruntime、调度类、实时调度、上下文切换、cgroup cpu
5信号与进程间通信信号投递、管道、消息队列、共享内存、信号量、Unix 域套接字
6物理内存管理struct page、Zone、伙伴系统、Slub 分配器、kmalloc/vmalloc、kswapd、OOM
7虚拟内存与 VMAmm_struct、vm_area_struct、缺页异常处理、COW、mmap、页表实现
8页缓存与 I/O 路径Page Cache、address_space、脏页写回、fsync、Direct I/O、io_uring
9VFS 与文件系统super_block/inode/dentry/file、dcache、ext4、procfs/sysfs/tmpfs
10块设备与 I/O 栈bio、blk-mq、I/O 调度器、I/O 优先级、NVMe 驱动模型
11设备驱动模型kobject、sysfs、字符/块/网络设备、udev、内核模块、DMA
12网络协议栈sk_buff、NAPI、TCP 状态机、Netfilter、网络命名空间
13中断与软中断IDT、Top Half/Bottom Half、Softirq、Tasklet、Workqueue
14内核同步机制原子操作、内存屏障、自旋锁、互斥锁、RCU、Futex、lockdep
15Cgroups 与 Namespaces7 种 Namespace、Cgroup v2 控制器、容器运行时
16安全机制Capabilities、SELinux、AppArmor、Seccomp-BPF、Audit
17内核模块.ko 结构、模块加载/卸载、符号导出、module_param、printk
18追踪与可观测性ftrace、perf、eBPF 程序/Map/验证器、bpftrace、BCC
19Linux 启动流程start_kernel、initramfs、pivot_root、systemd、内核命令行
20综合实战8 个真实问题诊断场景,综合运用前 19 章知识

五、开发环境搭建#

获取内核源码#

# 方式一:从 kernel.org 下载稳定版源码
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.7.tar.xz
tar -xvf linux-6.12.7.tar.xz
# 方式二:通过 git 克隆(包含完整历史,较大)
git clone --depth=1 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
# 方式三:使用 GitHub 镜像(国内速度更快)
git clone --depth=1 https://github.com/torvalds/linux.git

配置源码阅读环境#

# 安装代码阅读工具
sudo apt install cscope ctags universal-ctags
# 在内核源码根目录生成标签文件
make tags # 生成 CTAGS
make cscope # 生成 CSCOPE
# VSCode 用户:安装 C/C++ 扩展 + C/C++ Extension Pack
# 然后在 .vscode/c_cpp_properties.json 中配置内核源码路径

编译最小内核(用于实验)#

# 安装编译依赖
sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev
# 生成默认配置
make defconfig
# 自定义配置(可选)
make menuconfig
# 编译内核(-j 参数根据 CPU 核心数调整)
make -j$(nproc)
# 编译完成后在 QEMU 中启动
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -m 512M

内核源码目录结构#

linux/
├── arch/ # 架构相关代码(x86、arm、riscv 等)
├── block/ # 块设备层(blk-mq、I/O 调度器)
├── certs/ # 证书与签名
├── crypto/ # 加密 API
├── drivers/ # 设备驱动(占内核代码量最大)
├── fs/ # 文件系统(ext4、proc、sysfs 等)
├── include/ # 头文件
├── init/ # 内核初始化(start_kernel)
├── ipc/ # System V IPC
├── kernel/ # 核心子系统(调度、信号、模块等)
├── lib/ # 通用库函数
├── mm/ # 内存管理
├── net/ # 网络协议栈
├── samples/ # 示例代码(内核模块等)
├── scripts/ # 构建与工具脚本
├── security/ # 安全模块(SELinux、AppArmor)
├── sound/ # 音频子系统(ALSA)
├── tools/ # 用户态工具(perf、bpf 等)
├── usr/ # initramfs 构建
└── virt/ # 虚拟化(KVM)

六、本系列的实践方法论#

本系列遵循 观察 → 假设 → 验证 → 源码确认 的学习方法:

  1. 观察:通过 /proc/sysstraceperf 等工具观察内核行为
  2. 假设:根据观察结果,对内核的实现方式提出假设
  3. 验证:通过编写测试程序或修改内核参数验证假设
  4. 源码确认:阅读内核源码,确认理解是否正确

每章的「动手实践」部分都遵循这一方法论,让你不仅知道”是什么”,更理解”为什么”。

推荐参考资料#

经典教材#

书籍作者特点
《Linux 内核设计与实现》Robert Love聚焦 Linux 内核实现,实践性强,适合入门
《深入理解 Linux 内核》Daniel P. Bovet 等对内核各子系统深入剖析
《深入理解 Linux 网络技术内幕》Christian Benvenuti网络子系统实现详解
《Linux 设备驱动程序》Jonathan Corbet 等设备驱动开发的权威参考
《Systems Performance》Brendan Gregg性能分析与可观测性的百科全书
《操作系统导论》(OSTEP)Remzi H. Arpaci-Dusseau免费开源,对话式风格,适合建立宏观认知

在线资源#

源码阅读工具#

  • cscope:C 符号定义/引用查找,内核源码阅读的经典工具
  • ctags / universal-ctags:标签跳转,配合 Vim/Emacs 使用
  • Elixir Cross Referencer:在线版,无需本地配置
  • VSCode + C/C++ Extension:图形化 IDE 阅读体验
  • QEMU + GDB:内核动态调试,打断点、单步执行

准备好开始了吗?从 Linux 内核架构全景 开始你的 Linux 内核之旅吧!


参考#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

系列导读
https://blog.souloss.com/posts/linux-internals/linux-internals-series-guide/
作者
Souloss
发布于
2025-01-18
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时