進程是 Linux 系統調度的基本單位。本文構建進程管理完整知識體系:狀態機、父子關係、優先級、信號機制、IPC、核心工具鏈與排查實戰,助你從「會用 ps」進階到「懂調度、會調優、能排查」。
一、進程狀態機
| 碼 | 狀態 | 含義 | 典型場景 |
| R | Running/Runnable | 正在執行或就緒等待 CPU | 計算密集型、佔 CPU 高 |
| S | Sleeping (Interruptible) | 等待事件(I/O、鎖、定時器),可被信號喚醒 | 網路請求、鎖等待 |
| D | Disk Sleep (Uninterruptible) | 等待磁碟 I/O 完成,**不可被信號中斷** | NFS 掛掉、磁碟壞道、vfs 鎖 |
| T | Stopped | 收到 SIGSTOP/SIGTSTP,或被 debugger 暫停 | Ctrl+Z、gdb attach |
| Z | Zombie | 子進程退出,父進程未 wait() 回收,殘留 task_struct | 父進程忽略 SIGCHLD、bug |
| X | Dead | 即將被銷毀,極短暫 | 極難捕捉 |
關鍵洞察:D 狀態進程 **kill -9 也殺不死**,必須解決底層 I/O 掛點(umount、重啟存儲、重啟機器)。
二、父子關係與孤兒/殭屍
init (PID 1) ──┬── systemd (PID 1, 新系統)
├── sshd ──┬── bash ── vim
│ └── bash ── python app.py
├── cron ── backup.sh
└── nginx (master) ── nginx (worker) × N
- 孤兒進程:父進程先退出 → 由 init (PID 1) 收養 → init 定期
wait() 清理
- 殭屍進程:子進程退出,父進程未
wait() → 佔用 PID、task_struct → 大量殭屍耗盡 PID 上限
- 清理殭屍:殺死父進程 → 變孤兒 → init 回收;或修復父進程代碼加入
signal(SIGCHLD, handler) + waitpid(-1, NULL, WNOHANG)
三、優先級與 Nice
| 概念 | 範圍 | 說明 |
| Static Priority (RT) | 0-99 | 實時進程,SCHED_FIFO/RR,數字越小優先級越高 |
| Nice (用戶空間) | -20 ~ +19 | 預設 0,負數優先級高,需 root 權限調負數 |
| Dynamic Priority | - | 核心根據 nice、睡眠時間、I/O 等動態計算 |
# 查看
ps -eo pid,ni,pri,cmd | head
top - # 進入後按 r 改 nice,按 P/M/T 排序
# 調整
nice -n -5 ./high_priority_app # 啟動時指定(需 root)
renice -n 10 -p 12345 # 運行中調整(降低優先級)
四、信號機制
| 信號 | 編號 | 預設動作 | 典型用途 |
| SIGHUP | 1 | Terminate | 通知 daemon 重讀配置(kill -HUP) |
| SIGINT | 2 | Terminate | Ctrl+C 終止前台進程 |
| SIGQUIT | 3 | Core Dump | Ctrl+\ 強制退出並產生 core |
| SIGKILL | 9 | Terminate | **不可捕獲/忽略**,最後手段 |
| SIGTERM | 15 | Terminate | 優雅關閉,可捕獲做清理 |
| SIGSTOP | 19 | Stop | **不可捕獲**,暫停進程 |
| SIGCONT | 18 | Continue | 恢復 SIGSTOP |
| SIGCHLD | 17 | Ignore | 子進程退出通知父進程 |
# 發送信號
kill -15 12345 # 優雅關閉
kill -9 12345 # 強殺
kill -HUP 12345 # 重載配置
killall -15 nginx # 按名稱發送
pkill -f "java.*app" # 按完整命令列匹配
五、IPC(進程間通訊)
| 機制 | 特點 | 適用場景 |
| 管道 | 單向、父子/親緣、生命週期隨進程 | Shell 管線 cmd1 | cmd2 |
| 命名管道 (FIFO) | 單向、路徑化、無親緣要求 | 日誌收集、簡單 RPC |
| 訊號 | 異步、少量資訊、不可靠 | 進程控制、簡單通知 |
| System V 共享記憶體 | 高速、持久、需同步(semaphore) | 高效能資料交換 |
| POSIX 共享記憶體 | 介面現代、shm_open/mmap | 現代應用首選 |
| 訊息佇列 | 持久、帶優先級、系統限額 | 任務分發、解耦 |
| Socket (Unix Domain) | 雙向、流/資料包、支援傳 fd | 微服務通訊、Containerd/CRI |
六、核心工具鏈對照
| 工具 | 定位 | 殺手級特性 |
ps | 靜態快照 | ps -eo pid,ppid,ni,pri,pcpu,pmem,stat,cmd --forest |
top | 動態互動 | 按 1 顯示各 CPU、H 執行緒、c 完整命令 |
htop | 增強 top | 滾動、樹狀、殺進程 F9、篩選 F4 |
pidstat | 統計彙總 | pidstat -u -p ALL 1 類 vmstat 但按進程 |
vmstat | 系統級 | vmstat 1 觀察 r/b/si/so/cs/in |
strace | 系統呼叫追蹤 | strace -p 12345 -f -e trace=network |
perf | 效能分析 | perf top -g、perf record -g -p 12345 |
/proc/PID | 核心介面 | fd/、maps、stack、environ、cwd |
七、排查實戰:高 CPU、D 狀態、殭屍
# 1. 高 CPU 定位函數
pidstat -u -p PID 1
perf top -p PID -g
# 2. D 狀態定位阻塞點
cat /proc/PID/stack
# 例:[] nfs_wait_bit_killable+0x... → NFS 掛了
# 3. 殭屍定位父進程
ps -eo ppid,pid,stat,cmd | awk '$3~/^Z/ {print $1, $2, $4}'
# 殺父進程或修復代碼
# 4. 記憶體洩漏
cat /proc/PID/smaps | grep -E '^(Size|Rss|Pss|Shared_Clean|Private_Dirty)' | awk '{sum+=$2} END {print sum/1024 " MB"}'
結語: 進程管理不只是背狀態碼,而是理解「調度怎麼決策、信號怎麼傳遞、IPC 怎麼選型、工具怎麼組合」。把 /proc、perf、strace、pidstat 串起來,下次遇到「CPU 100%、進程卡死、記憶體暴漲」,你有完整的排查地圖。