# 策展 · X (Twitter) 🔥🔥

> 作者：cheesecake (@cheese_cakee_9) · 平台：X (Twitter) · 日期：2026-04-27

> 原始來源：https://x.com/cheese_cakee_9/status/2048682528744018242

## 中文摘要

# Systems Programming 101

以下文章概述了構成電腦系統最重要且歷久彌新的概念。

---

## 到底什麼是 Systems Programming

Systems programming 是編寫介於硬體與其上層軟體之間的軟體行為。我們使用的應用程式生活在一個舒適、被抽象化的世界裡，充滿了字串與 HTTP 請求。而 Systems programming 就是讓這種舒適成為可能的工作：記憶體分配器 (memory allocators)、排程器 (schedulers)、檔案系統 (file systems)、網路堆疊 (network stacks)、裝置驅動程式 (device drivers)、執行時期 (runtimes)、編譯器 (compilers) 以及容器 (containers)。如果你的程式碼主要工作是讓其他程式碼正確且有效率地執行，那你就是在進行 Systems programming。

區分系統程式碼與應用程式碼的關鍵特性在於：資源鄰近性 (resource proximity)。在 Systems programming 中，CPU 時間、記憶體位址、檔案描述子 (file descriptors)、中斷 (interrupts) 等都是被直接處理或互動的。因此，當犯錯時沒有後備方案，錯誤會直接顯現為 segfaults、kernel panics 或無聲的資料損毀等。

正如 Julia Evans 所言，深入理解底層系統，是區分出能解決困難問題的工程師與只能解決簡單問題的工程師的關鍵。

## 這一切從哪裡開始

這一切都始於單一指令。處理器從記憶體中提取 (fetch) 指令，解碼 (decode) 其含義，執行 (execute) 它，然後移動到下一個指令。

提取。解碼。執行。

每一個曾在馮紐曼架構 (Von Neumann machine) 上執行的程式、每一個資料庫、每一個遊戲、每一個作業系統，都是這個每秒重複數十億次的迴圈。現代系統的複雜性，不過是建立在這個原始循環之上的工程技術。

但記憶體並非均質的。暫存器 (registers) 的存取時間僅需幾奈秒，而主記憶體 (DRAM) 則需要一百奈秒。這種差異看似微不足道，但往往是區分軟體能否大規模擴展的關鍵。Ulrich Drepper 在 2007 年寫道，隨著 CPU 核心變得更快且數量更多，大多數程式的限制因素將會是記憶體存取。這在現在比以往任何時候都更真實。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1777306760488-iaHG5guCRaUAARG80jpg.jpg)

硬體並非魔法。它是權衡取捨的層級結構——速度對抗大小、延遲對抗頻寬——而能深刻理解這一點的工程師，所寫出的程式碼與不理解的人有本質上的不同。

## 到底什麼是作業系統 (Operating System)

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1777306760609-diaHG5gI7bcAE0Kw7jpg.jpg)

硬體之上是作業系統，它的工作是「欺騙」，且是往最好的方向欺騙。它給予每個正在執行的程式一種擁有整台機器的錯覺，例如：它擁有自己的私有記憶體、自己的 CPU、自己的檔案。

作業系統解決的三個基礎問題是：虛擬化 (virtualization，給每個程式獨佔硬體的錯覺)、並發 (concurrency，讓多個任務同時發生而不互相干擾)，以及持久化 (persistence，讓資料在處理程序生命週期結束後依然存在)。這正是 OSTEP (Operating Systems: Three Easy Pieces) 書中架構自身的方式。

處理程序 (process) 並非程式 (program)。程式是磁碟上的位元組。處理程序是活著的程式，擁有位址空間、堆疊 (stack)、檔案描述子，以及核心 (kernel) 代為保存的一組暫存器。系統呼叫 (system calls) 是這兩個世界之間的接縫。你的程式無法直接觸碰硬體，它必須發出請求。CPU 會切換權限層級（從使用者模式切換到核心模式），核心執行工作，然後控制權再交還。

## 什麼是 Kernel？

Kernel 是電腦作業系統核心的電腦程式，始終對系統中的一切擁有完全控制權。Kernel 也負責防止與緩解不同處理程序之間的衝突。它是作業系統程式碼中始終駐留在記憶體中的部分，並促進硬體與軟體組件之間的互動。

當你的處理程序認為它擁有 CPU 時，那是排程器在維持這種錯覺——讓你的處理程序執行一段時間，保存其暫存器，切換到下一個，恢復它們，然後繼續執行。當你的指標解析到實體記憶體時，那是記憶體管理器在遍歷核心為你建立並維護的頁表 (page tables)。當網路封包到達時，Kernel 的中斷處理程式會喚醒，NIC (網路介面卡) 將資料透過 DMA 傳輸到 Kernel 緩衝區，TCP 堆疊將其重組，然後你的 `recv()` 才會回傳。這一切對你的程式來說都是不可見的。這一切都在它之下發生，每一次都是如此。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1777306761386-iaHG5gfhVasAAV66Djpg.jpg)

正如 Julia Evans 所言：理解一些關於 Kernel 和 Systems programming 的基礎知識能讓你成為更好的開發者，並且你可以在除錯日常程式時運用這些知識。

## 記憶體 (Memory)

每個非瑣碎的系統程式最終都必須認真思考記憶體問題。記憶體是大多數系統錯誤存在的地方，也是大多數系統效能贏得或失去的地方。你的程式所使用的虛擬位址並非實體位置。MMU (記憶體管理單元) 會在每次存取時使用 Kernel 維護的頁表進行轉換。尚未需要的頁面不會被載入。來自 `fork()` 的頁面會被共享，直到其中一個處理程序進行寫入，此時 Kernel 會靜默地僅複製發生變更的頁面。檔案會被直接映射到位址空間中。

`malloc()` 並非魔法——它呼叫 `mmap()` 和 `brk()` 從 Kernel 獲取大塊記憶體，然後自行細分並追蹤這些區塊。堆積分配器 (heap allocator)、頁表遍歷器、TLB、快取層級 (cache hierarchy)：每一層都是系統設計者對程式行為方式所下的賭注。系統工程師的優勢在於知道這些賭注下在哪裡。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1777306760357-iaHG5hhlxbAAEHmsyjpg.jpg)

## 並發 (Concurrency)

OSTEP 直接點出了核心問題：單一實體 CPU 被許多處理程序共享，但每個處理程序都必須表現得好像它完全擁有 CPU 一樣。一旦你加入了執行緒 (threads) 和共享記憶體，這種錯覺就會變得危險。一個執行緒讀取一個值，另一個執行緒寫入它。硬體對於這些操作完成的順序不做任何保證。Mutexes、條件變數 (condition variables)、原子操作 (atomics) 並非便利工具，而是編寫在不提供任何保證的硬體上執行之程式碼的入場費。

![](https://pub-75d4fe1e4e80421b9ecb1245a7ae0d1a.r2.dev/curated/1777306760423-iaHG5fVBzboAAdUKkjpg.jpg)

## 工具鏈 (The Toolchain)

大多數程式設計師將編譯視為一個黑盒子。但要成為一名系統工程師，你需要看透它，因為工具鏈的決策直接影響正確性、效能與二進位檔案的佈局。

Ian Lance Taylor 在他那篇權威文章的開頭寫道：「連結器 (linker) 將目的檔 (object files) 轉換為可執行檔與共享函式庫。」這就是它的全部工作。編譯器產生組合語言。組譯器 (assembler) 產生帶有未解析名稱的目的檔——連結器必須在其他檔案或函式庫中為這些符號找到定義。在 Linux 上，ELF 是容納這一切的格式：`.text` 中的程式碼、`.data` 中的已初始化資料、作為重定位條目 (relocation entries) 的未解析參考，連結器會在二進位檔案準備執行前修補這些條目。工具鏈：編譯器、組譯器、連結器、載入器 (loaders)，讓每一步都變得可見。

## 那麼，這會帶你去向何方？

如果你致力於學習本文所觸及的概念，你將邁向成為一名稀有的「強大程式設計師 (power programmer)」，並因對底層電腦系統的理解而開悟。這種理解並不屬於單一領域。安全工程師利用系統工程師所設計的相同記憶體佈局；ML 基礎設施工程師在相同的快取層級邏輯上進行優化；資料庫工程師構建緩衝池 (buffer pools)、預寫式日誌 (write-ahead logs)、B-trees 等，這些全都是系統專案。編譯器工程師與執行時期工程師永久居住於此。平台工程師與執行容器的 SRE 正在使用命名空間 (namespaces) 與 cgroups，這些本質上就是經過包裝的 Kernel 原語。我們用來除錯的每一個工具，都是由理解底層運作原理的人所構建的。

記憶體、排程與 I/O 的物理特性永不過時。它們是電腦科學的基礎與根本。問題會改變，但基礎不會。這篇文章只是一個簡化的概述！並提醒你應該永遠保持好奇心！閱讀愉快！

~cheesecake

## 標籤

教學資源, 其他
