前三天我們一直提到一個詞:Process。
例如 CPU 正在執行 Process A、System Call 由某個 Process 發出,甚至 Interrupt 發生之後,CPU 最後可能還要回去繼續執行原本的 Process。
但 Process 到底是什麼?一個 Process 不只有程式碼。
它還必須記得:
程式執行到哪裡、用了哪些記憶體、暫存器現在是什麼值、開了哪些檔案,以及目前到底能不能繼續執行。
假設電腦裡有一個:
hello.exe
或 Linux 中的一個 executable file。
這個檔案本身是一個** Program。**
它包含可以被載入執行的機器指令,以及程式執行需要的其他資訊。
但只要我們沒有執行它,它基本上就只是儲存在儲存裝置上的一份資料。
當我們啟動這個 Program 時,OS 需要建立執行它所需要的環境,例如:
如果 Process 只是程式碼,那 OS 根本不需要特別建立 Process 這個抽象的東西。
所以:Process 代表的是一個完整的執行環境,除了程式內容之外,OS 還必須保存它的執行狀態、記憶體狀態,以及它正在使用或有權使用的各種系統資源。
Process
│
├── Memory / Virtual Address Space
│ ├── Code / Text
│ ├── Data / BSS
│ ├── Heap
│ ├── Stack
│ └── Memory Mappings
│
├── CPU Execution State
│ ├── Program Counter
│ ├── Stack Pointer
│ ├── Registers
│ └── 其他 CPU Context
│
├── OS Management Information
│ ├── PID
│ ├── Process State
│ ├── Scheduling Information
│ ├── Parent / Child 關係
│ └── Accounting 等資訊
│
├── Resources
│ ├── Open Files / File Descriptors
│ ├── I/O-related Resources
│ └── 其他 Kernel Resources
│
└── Execution Environment
├── Credentials / Permissions
├── Signal-related State
├── Working Directory
└── 其他執行環境資訊
程式執行一定需要記憶體,這時候virtual address space就出現了。
假設現在電腦上根本不只有一個 Process。
Process A → Browser
Process B → VS Code
Process C → Music Player
它們都需要記憶體。
如果所有 Process 都直接操作同一套 Physical Memory Address,那每個程式都必須知道:
A 可以用哪裡?
B 可以用哪裡?
C 又可以用哪裡?
講難聽的,如果 Process A 可以直接隨意存取 Physical Memory,它就可能讀取甚至修改 Process B 正在使用的資料,一個程式的 Bug,都可能直接破壞另一個程式。
為了避免這個問題,現代 OS 通常不會讓 User Process 直接把 Physical Address 當成自己的程式位址來使用。
Process A 的 0x1000 和 Process B 的 0x1000,不一定代表同一個 Physical Memory Location。
兩個 Process 都可以覺得:「這是我的 0x1000。」
但 OS 搭配硬體的記憶體管理機制,可以讓它們最後對應到不同的 Physical Memory。
這就是 Virtual Address 很重要的地方。
那 Virtual Address 怎麼變成 Physical Address?
Virtual Address
│
▼
Address Translation
│
▼
Physical Address
│
▼
Physical Memory
這個轉換通常由硬體的 MMU(Memory Management Unit) 搭配 OS 所建立的 Page Table 等機制完成。
假設 CPU 正在執行:
a = 10;
b = 20;
c = a + b;
printf("%d", c);
如果執行到c = a + b;
突然被 OS 暫停。
那之後恢復這個 Process 時,CPU 怎麼知道自己剛才執行到哪裡?
這就是 CPU Execution State 很重要的原因。
包含像:Program Counter(PC,在不同架構可能有不同名稱)用來表示 CPU 接下來要執行的指令位置。
Registers
CPU 執行指令時,大量中間狀態會放在 Registers 裡。
例如計算c = a + b;
實際執行時可能需要把資料放進 CPU registers,再進行運算。
所以如果 Process A 執行到一半:
Register 1 = ...
Register 2 = ...
PC = ...
SP = ...
接著 CPU 跑去執行 Process B。
B 當然也會使用 CPU 的 Registers。
如果 A 原本的 register state 沒有被妥善保存,等 A 回來時,它原本的執行狀態就可能已經消失。
在 OS 教材中,常用一個抽象名稱:
PCB — Process Control Block
可以把 PCB 理解成:OS 用來保存與管理 Process 相關資訊的核心資料結構概念,例如:
PCB
│
├── Process ID
├── Process State
├── CPU Context
│ ├── Program Counter
│ ├── Stack Pointer
│ └── Registers
├── Scheduling Information
├── Memory Management Information
├── Open Files / I/O Information
└── Other Process Metadata
所以當 CPU 暫時不執行 Process A 時:
Process A 並沒有因此消失。
Kernel 還保留著描述它的資訊與相關資源,讓它之後有機會繼續執行。
Process 並不是各自真的拿到一整段連續 RAM。
每個 Process 使用自己的 Virtual Address,而 OS 與硬體負責把它們映射到真正的 Physical Memory,並控制哪些記憶體可以被存取。
下一個問題則是:
如果 Process A 正在 CPU 上執行,而 OS 決定改成 Process B:
A 的 Program Counter、Stack Pointer、Registers 怎麼辦?B 上一次的 CPU 狀態又要怎麼恢復?
這就是下一篇: