fork() 是 Unix 最有辨识度的设计:一次调用,两次返回。它经常被当作「优雅」的范例,也经常被批评为「过时的错误」。 这一篇要说清楚:它为什么长这样、它的优
10 篇讲了 uid/gid 的操作,这一篇讲它们为什么长成这样 —— 特别是那个让无数人困惑的问题:为什么一个进程需要四套 uid? 先看五个问题: 为什么需要 ruid/euid/suid/fsuid 四套 u
10 篇讲了权限的操作,22 篇讲了凭证模型。这一篇把它们串成一条五十年的时间线 —— 每一层机制都是为了补上前一层的缺陷而出现的。 先看五个问题: 为什
虚拟内存是操作系统最昂贵的抽象:每一次内存访问都要经过地址翻译。这一篇讲它为什么值得。 先看五个问题: 虚拟内存最初解决的是什么问题?为什么值得
24 篇讲的是「虚拟地址如何映射到物理页」。这一篇讲那些物理页本身是怎么被管理的 —— 从分配到回收到杀进程。 先看五个问题: buddy 分配器怎么对抗外部碎片
25 篇讲了内核如何管理物理页。这一篇讲用户态如何把「页」切成「对象」 —— 以及为什么每个大型运行时(glibc、Go、JVM、Redis)都要自
前两篇讲内存 —— 一种可以超卖但不能压缩时间的资源。这一篇讲 CPU:一种完全不能存储的资源。内存分配错了顶多慢、顶多 OOM,CPU 分配错了直接
上一篇讲调度器如何决定「谁能运行」。这一篇讲并发程序里更常见的问题:明明调度器愿意让线程运行,线程却因为一把锁主动放弃 CPU。 锁看起来只有两
前一篇的 futex 把「等某个内存值变化」变成了可控的同步协议。这一篇看 Linux 里更古老、也更不规整的一套通知机制:信号(signal)。 信号最初诞生于 Unix 早
上一篇讲信号如何把异步事件插进进程控制流。这一篇把视线移到数据:文件系统为什么不能只是一张「文件名 → 磁盘位置」的表? 你每天都在写文件:日志追
上一篇讨论文件数据如何从页缓存到稳定介质。这一篇讨论另一条高频路径:网络连接上的数据什么时候可读、什么时候可写,以及一个进程如何同时管理十万
上一篇讲 epoll 如何告诉应用“哪个 fd 现在可以读写”。这一篇继续沿着 IO 路径往下走:如果连每次提交 IO 都要一次系统调用,数据还要在用户态和内核态来回复制
上一篇讲 io_uring、sendfile 等接口如何降低应用提交 IO 的控制面成本。这一篇沿反方向追问:当网络字节抵达机器时,内核怎样把它变成某
上一篇沿着收包路径,从网卡 DMA、NAPI、sk_buff 一直走到 socket 接收队列。这一篇站到应用侧:为什么一个普通整数 fd 能代表一条跨机器的 TCP 连接
上一篇从应用视角拆解 socket:一个 fd 如何经历 bind、listen、accept、connect 和收发。这一篇把进程放进容器后再追问:容
上一篇用 network namespace、veth、bridge、路由和 NAT 解释了容器为什么能联网。这一篇把视角扩大:容器看起来有自己的 PID 1、根目录、主机
上一篇讲 namespace 改变进程视图、cgroup 约束资源。这一篇回到系统启动的第一个用户态进程:当一台机器有数百个长期服务、设备可能热插拔、网络异步就绪
上一篇讲 systemd 如何统一管理服务生命周期与日志。这一篇继续追问:服务已经运行,P99 突然升高,但 CPU 平均值正常、日志没有 error、重启后暂时恢复,
前 38 篇已经分别拆开 CPU、内存、调度、锁、文件系统、网络、容器、systemd 和 eBPF。这一篇不再按机制讲,而是把它们重新放回事故现场:用
前 39 篇从进程、虚拟内存、调度、futex、信号、VFS、epoll、io_uring、网络收包、socket、容器、cgroup、syste