fork() 創建子進程時,記憶體佈局發生什麼變化?理解這一機制對高效編寫多進程程式、診斷記憶體問題至關重要。
| 記憶體區域 | 子進程擁有 | 共享/複製機制 | 備註 |
|---|---|---|---|
| 代碼段 (Text) | 否 | 共享 | 只讀,父子映射同一物理頁框 |
| 資料段 (Data) | 是 | Copy-on-Write | 初始共享,寫入時複製 |
| 堆 | 是 | Copy-on-Write | malloc 區域同 COW |
| 堆疊 | 是 | Copy-on-Write | 各自獨立生長 |
fork() 只複製頁表、建立 COW 標記,不複製實際內容,極快(微秒級)execve() 載入新程式、malloc/free 操作堆fork() 後立即 exec()(Shell 啟動程式典型模式)#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int global = 100;
int main() {
int local = 200;
pid_t pid = fork();
if (pid == 0) { // 子進程
printf("Child: global=%d (addr=%p), local=%d (addr=%p)\n",
global, &global, local, &local);
global = 300; // 觸發 COW
local = 400;
printf("Child after write: global=%d, local=%d\n", global, local);
} else { // 父進程
sleep(1); // 等待子進程修改
printf("Parent: global=%d (addr=%p), local=%d (addr=%p)\n",
global, &global, local, &local);
wait(NULL);
}
return 0;
}
輸出:
Child: global=100 (addr=0x55a...), local=200 (addr=0x7ff...)
Child after write: global=300, local=400
Parent: global=100 (addr=0x55a...), local=200 (addr=0x7ff...)
虛擬地址相同,物理頁寫入後分離,父進程數值未變。
exec(),現代 Linux 已合併實現fork()/pthread_create()/vfork() 均基於此,透過 flags 控制共享程度 (CLONE_VM, CLONE_FS, CLONE_FILES...)fork() 後盡快 exec() 或 _exit(),減少 COW 開銷fork(),考慮 posix_spawn() 或線程池mmap(MAP_SHARED) 或 System V 共享記憶體