第 1 章 · 计算机底层:从晶体管到进程

“所有的高级抽象,最终都要落回这块硅片上。你逃不掉。“


本章覆盖的课程

编号课程本章对应的产出
131操作系统实战45讲手写引导程序 + 内核初始化 + 进程调度
069趣谈Linux操作系统系统调用、内存管理、进程模型全景
161深入 C 语言和程序运行原理从 C 源码到机器指令的完整链路
156编程高手必学的内存知识虚拟内存、分页、局部性、缓存行
050编译原理之美词法/语法/语义分析的理论基础
086编译原理实战课用 Go 实现一个完整的 C 子集编译器

本章要解决的问题

小林在一家做实时数据平台的公司,负责一个 Go 写的流式计算服务。某天凌晨三点,服务开始周期性卡顿——P99 从 8ms 飙到 900ms,持续 40 秒,然后自己恢复。监控上 CPU、内存、GC 全正常。

运维重启了机器,问题消失。一周后又出现。

小林查了一周,把 Go 代码翻了个底朝天,profile 打了几十份,什么都没找到。最后是一个老同事路过说了一句:

“你这个机器的 NUMA 节点是不是跨了?”

那一刻小林意识到:他一直在 Go 这一层找问题,但问题在 Go 下面第 4 层。

这一章,就是要帮你建立那个”第 4 层”的视角。


章节结构

文档内容预计字数
00-设计推演:从零造一个内存分配器.md★ 建议先读:mmap → 批发bump → 空闲链表 → size class → 三层缓存 → tiny/large 的七次失败演进6,000
01-开篇-一次查不出的P0事故.md从 NUMA 事故切入:你以为的”内存”是什么5,000
02-程序是怎么跑起来的.mdgo build 到 CPU 取指,完整链路拆解5,500
03-内存的本质.md虚拟地址、页表、TLB、缓存行、NUMA6,000
04-动手-用Go写内存分配器.md从 mmap 到 size class 到 thread cache6,500
05-编译原理-从字符到语法树.md词法、语法、语义三阶段6,000
06-动手-用Go写C编译器.md递归下降 + 代码生成 + 目标文件6,500
07-操作系统-进程调度与系统调用.md特权级、中断、上下文切换、调度器6,000
08-动手-从引导扇区到内核.md写一个能启动的最小内核5,500
09-链接装载与程序启动.md静态链接、动态链接、ELF、进程诞生5,000
10-章节总结与能力自测.md知识图谱 + 30 道自测题4,000

合计约 5.6 万字(超出 3 万字要求,因为这一章是地基)。


学完这一章,你应该能

  1. 画出从 C 源码到 CPU 执行的完整数据流,指出每一步的中间产物是什么。
  2. 解释一次 malloc(8) 背后,内核态和用户态分别做了什么。
  3. 说清楚为什么 false sharing 能让多线程程序慢 5 倍,并写出复现代码。
  4. 手写一个能工作的内存分配器,性能达到 glibc malloc 的 60% 以上。
  5. 用 Go 实现一个能编译 C 子集(含指针、结构体、函数、控制流)的编译器。
  6. 写出一个能从 BIOS 引导、进入保护模式、打印字符的最小内核。
  7. 解释 go build 出来的二进制文件里,每一个 section 是干什么的。

这一章为什么最难

因为它要求你同时在四个抽象层级思考:

┌─────────────────────────────────────┐
│  层级 4:语言    Go/C 的语义          │  ← 你习惯在这里
├─────────────────────────────────────┤
│  层级 3:运行时  编译器、链接器、ABI    │
├─────────────────────────────────────┤
│  层级 2:OS      虚拟内存、进程、调度   │
├─────────────────────────────────────┤
│  层级 1:硬件    CPU、缓存、总线、MMU  │  ← 问题往往根在这
└─────────────────────────────────────┘

大多数工程师只在层级 4 工作,遇到怪问题就束手无策。 能下到层级 2 的人,已经能解决 90% 的疑难杂症。 能下到层级 1 并回来的人,才有资格设计系统。


阅读建议

  • 不要跳。这一章的内容是强依赖的,跳过 03 直接看 04 会看不懂。
  • 代码一定要跑。特别是 04 和 06,光看代码没用,跑起来加个 fmt.Println 看看中间态。
  • 思考题先自己答。参考答案是”老陈的答案”,不是”标准答案”,你有更好的答案就说明你真的懂了。

开始阅读:00-设计推演:从零造一个内存分配器

两种读法:想先建立”设计感”的,从 00 开始(它用一整篇演示了怎么从失败里推出 Go 分配器的每个设计点); 想先看真实事故的,直接跳 01。两条线在 03-内存的本质 汇合。