行程 vs 程式
初學者常見的混淆,是把「程式」和「行程」當成同一回事來用。它們不是。程式像樂譜:一份靜靜躺在磁碟上的檔案,每次你看它都是同樣的位元組,本身什麼也不做。行程則是此刻正在演奏那份樂譜的管弦樂團:一場動態、活生生的演出,有開始、佔用了音樂廳、耗用時間與能量,最後會結束。同一份樂譜可以被演奏許多次,由許多樂團同時上演。
精確地說:程式是可執行檔——存在磁碟上的已編譯指令與初始資料,外加把它排佈進記憶體的規則。行程是那個程式的一個執行中實例:核心從程式建立出來的一個私有定址空間、一份 CPU 暫存器狀態、一組開啟的檔案、一個 PID,以及核心行程表裡的一筆紀錄。程式是架上的名詞;行程是運行中的動詞。把同一個程式執行兩次,會建立出兩個不同的行程,PID 不同、記憶體不同,即便它們是從同一個檔案讀取指令。
為何重要:這個欄位裡幾乎每個令人困惑的問題,只要你抓住這個差別就會豁然開朗。「有幾份 Chrome 在執行?」問的是行程,不是那一個 Chrome 程式檔。fork() 造出的是新行程,不是新程式。當一個程式結束,我們說的是行程終止了,而檔案原封不動。把兩者混為一談會講出聽起來沒問題、其實是胡說的句子,例如「那個程式吃掉了 40% 的 CPU」——吃掉 CPU 的是行程,因為只有運行中的東西才能用掉任何東西。
ls 是一個程式:位於 /bin/ls 的一個檔案。每次你在 shell 裡打 ls,作業系統就從那個檔案建立一個全新的行程,它執行幾毫秒、印出名稱、然後行程結束。檔案 /bin/ls 從沒改變過;來來去去的是許多短命的行程。
一個不變的程式檔,孕育出許多各自獨立、短命的行程。
口語上常把兩者混著講(「跑那個程式」),閒聊時無妨。但在推敲資源、排程、PID 或 fork/exec 時,請逼自己講清楚指的是哪一個——是檔案,還是執行中的實例。