ps 命令是最常用的工具之一。但很多人只知道 ps aux,却不了解背后的实现原理。今天我们来深入解析这个命令。
ps 命令的核心:读取 /proc 文件系统
ps 命令并不直接调用系统 API,而是读取 /proc 虚拟文件系统:
# ps 命令的本质就是读取这些文件ls /proc/1234/# cmdlin comm cwd exe fd maps stat status ...
每个进程在 /proc 下都有一个以 PID 命名的目录,里面有各种文件记录进程信息:
- cmdline
- comm
- stat
- status
- fd/
- exe
理解 ps aux 输出的每一列
ps aux# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND# root 1 0.0 0.1 169424 11200 ? Ss May08 0:05 /sbin/init
关键字段详解
VSZ (Virtual Memory Size)
RSS (Resident Set Size)
STAT (进程状态)
- R
- S
- D: Disk sleep(不可中断睡眠,通常在等 I/O)
- Z: Zombie(僵尸进程,已终止但父进程未回收)
- T
状态后面的修饰符:
%CPU 的计算原理
ps 计算 CPU 使用率的公式:
%CPU = (进程总 CPU 时间 / 进程运行总时间) * 100
但这有个陷阱:ps aux 显示的是进程启动以来的平均 CPU 使用率,不是实时值!
一个进程启动后跑了 1 秒 CPU,然后休眠 1 小时,ps 显示的 %CPU 会非常低。
要查看实时 CPU 使用率,需要用 top 或 pidstat。
实战案例:定位高 CPU 进程
案例 1: 找出 CPU 占用最高的进程
# --sort=-%cpu 按CPU降序排列ps aux --sort=-%cpu | head -10# 输出# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND# mysql 10234 78.5 15.2 4523124 1.2g ? Sl May08 123:45 /usr/sbin/mysqld
案例 2: 查看进程的线程信息
# -L 显示线程,LWP 是线程 IDps -Lp 10234# PID LWP TTY STAT TIME COMMAND# 10234 10234 ? Sl 0:05 mysqld# 10234 10235 ? Sl 0:12 mysqld# 10234 10236 ? Sl 0:08 mysqld
LWP (Light Weight Process) 就是线程 ID,在 Linux 中线程本质上是轻量级进程。
案例 3: 查看进程树关系
# --forest 显示父子进程关系ps auxf# 或用 pstree 命令pstree -p 10234
案例 4: 找出僵尸进程
# 查找状态为 Z 的进程ps aux | awk '8 ~ /D/'# 处于 D 状态的进程通常在等 NFS、磁盘 I/O# kill -9 也无法杀死,只能等待 I/O 完成
Web 实现:浏览器端的进程监控
虽然浏览器无法直接访问 /proc,但可以通过 API 转发:
// 后端 API: /api/processesexport async function GET() { const fs = require('fs') const processes = [] // 读取 /proc 目录下的所有数字目录(进程) const pids = fs.readdirSync('/proc').filter(d => /^\d+{pid}/stat`, 'utf-8') const comm = fs.readFileSync(`/proc/${pid}/comm`, 'utf-8').trim() // 解析 stat 文件(格式复杂,用空格分割) const parts = stat.split(' ') const utime = parseInt(parts[13]) // 用户态时间 const stime = parseInt(parts[14]) // 内核态时间 processes.push({ pid: parseInt(pid), name: comm, utime: utime, stime: stime, state: parts[2] // 进程状态 }) } catch(e) { // 进程可能已退出 } } return Response.json(processes)}
前端展示:
function ProcessList() { const [processes, setProcesses] = useState([]) useEffect(() => { const interval = setInterval(async () => { const res = await fetch('/api/processes') const data = await res.json() setProcesses(data) }, 1000) return () => clearInterval(interval) }, []) return ( <table> <thead> <tr> <th>PID</th> <th>Name</th> <th>State</th> <th>CPU Time</th> </tr> </thead> <tbody> {processes.map(p => ( <trkey={p.pid}> <td>{p.pid}</td> <td>{p.name}</td> <td>{p.state}</td> <td>{p.utime + p.stime}</td> </tr> ))} </tbody> </table> )}
总结
ps 命令看似简单,实则蕴含了 Linux 进程管理的核心知识:
- 数据来源
- 关键字段: VSZ(虚拟)、RSS(真实)、STAT(状态)
- 性能指标
- 高级用法
- 常见陷阱
掌握 ps 命令,是 Linux 性能排查的基础。
相关工具: