ps —— 进程快照
ps —— 进程快照
分类:02 进程与网络诊断 适用:所有 Linux(procps-ng) 一句话:瞬时快照、输出稳定、可自定义列,是脚本与排障的基础工具。
1. 它解决什么问题
- 进程还在不在?跑了多久?父进程是谁?
- 启动参数到底是什么(很多问题看启动参数就明白了)。
- 批量统计:内存总和、线程数、进程数、僵尸进程。
ps 是快照,不刷新;要持续观察用 top/pidstat。
2. 两种语法
| 风格 | 写法 | 特点 |
|---|---|---|
| BSD | ps aux |
常用,列固定 |
| UNIX | ps -ef |
常用,列固定 |
| 自定义 | ps -eo ... |
想显示什么写什么,推荐 |
ps aux # 所有进程,BSD 风格
ps -ef # 所有进程,UNIX 风格,含 PPID
ps -eo pid,ppid,user,stat,pcpu,pmem,etime,cmd
3. 常用命令
ps aux | grep -v grep | grep nginx # 查进程(避免匹配到 grep 自身)
pgrep -af nginx # 更干净:-a 显示命令行
ps -ef --forest | grep -A5 nginx # 树状,看子进程
ps -p 1234 -o pid,ppid,user,stat,etime,cmd # 指定 PID
ps --ppid 1234 # 看某进程的所有子进程
ps -C nginx -o pid,cmd # 按命令名精确匹配
ps -u nginx # 按用户
ps -eLf # 显示线程(LWP)
ps -T -p 1234 # 该进程的线程
ps -eo pid,cmd --sort=-pcpu | head # 按 CPU 降序
ps -eo pid,cmd --sort=-rss | head # 按内存降序
ps -eo pid,lstart,etime,cmd -p 1234 # 精确启动时间 + 已运行时长
4. 自定义列(-o)
| 列名 | 含义 |
|---|---|
pid ppid |
进程号、父进程号 |
pgid sid |
进程组、会话 ID(判断是否被 nohup/setsid 托管) |
user uid |
运行用户 |
stat |
状态码(见下) |
pcpu pmem |
CPU、内存百分比(开机以来平均,不是瞬时) |
vsz rss |
虚拟内存、常驻内存(KB) |
etime |
已运行时长([[DD-]hh:]mm:ss) |
lstart |
精确启动时间 |
time |
累计 CPU 时间 |
nice pri |
优先级 |
cmd / args |
命令行(comm 只要程序名) |
wchan |
内核等待通道(排查 D 状态必用) |
nlwp |
线程数 |
STAT 状态码
| 码 | 含义 | 备注 |
|---|---|---|
R |
运行中/可运行 | |
S |
可中断睡眠 | 大多数进程的正常状态 |
D |
不可中断睡眠 | IO 卡住,kill -9 也杀不掉 |
Z |
僵尸 | 父进程未回收 |
T |
停止(被 SIGSTOP/job control) | |
t |
被调试器停止 | |
I |
空闲内核线程 | 新内核 |
< |
高优先级 | |
N |
低优先级 | |
L |
有页面锁定在内存 | |
s |
会话首进程 | |
l |
多线程 | |
+ |
前台进程组 |
组合如 Ss、Ssl、R<。
5. 实战场景
5.1 找出所有僵尸进程及其父进程
ps -eo stat,ppid,pid,cmd | awk '$1 ~ /^Z/'
# 处理:修父进程,或 kill 父进程让 init 收养
5.2 定位卡在 IO 的进程
ps -eo pid,stat,wchan:32,cmd | awk '$2 ~ /D/'
wchan 显示内核里等什么,如 nfs_wait、io_schedule、rpc_wait_bit_killable。
5.3 统计进程真实内存占用
# RSS 求和(会重复计共享内存,仅粗算)
ps -eo rss --no-headers | awk '{s+=$1} END {printf "RSS 合计: %.2f GB\n", s/1024/1024}'
# 更准:用 smem 的 PSS
smem -t -k | tail -3
5.4 查服务启动参数
ps -p $(pgrep -f 'java.*app.jar') -o args= | tr ' ' '\n' | grep -E '^-X|^-D'
tr '\0' '\n' < /proc/1234/cmdline # 最原始、最可靠
很多"配置改了不生效"的问题,看这里就发现进程还带着旧参数。
5.5 统计线程数与进程数
ps -eLf --no-headers | wc -l # 线程总数
ps -e --no-headers | wc -l # 进程总数
ps -o nlwp= -p 1234 # 单进程线程数
cat /proc/1234/status | grep Threads
线程数触及 kernel.threads-max 或 pids.max(容器)会报 fork: Cannot allocate memory。
5.6 树状看谁拉起了服务
ps -ejH # 按会话/进程组树状
ps axjf # 经典树状
pstree -p 1234 # 更直观(需 psmisc)
pstree -u -p | head -40
判断进程是被 systemd、supervisor、shell 还是 cron 拉起的,决定重启方式。
6. 常见坑
ps aux的%CPU是开机以来平均,不是当前值。看瞬时用top/pidstat。grep xxx会匹配到自己:用grep -v grep或直接pgrep -af。ps aux截断命令行:终端宽度限制,用ps -eo cmd --width 300或cat /proc/PID/cmdline。- 容器内只看到自己的进程:PID namespace 隔离,宿主机
ps里容器进程 PID 与容器内不同。 STAT的D杀不掉不是权限问题:是内核态不可中断,只能等 IO 超时或修存储。ps -ef的CMD列含完整路径但COMMAND可能折行,脚本解析用-o固定列。ps在某些精简镜像(Alpine busybox)参数不同:busybox 版ps只支持ps、ps aux有限列,装procps包。- PID 会复用:长时间脚本记录 PID 时同时记
lstart,避免误杀新进程。 ps -C匹配的是comm(15 字符截断),长程序名要用pgrep -f。
7. 速查表
ps aux # 全量(BSD)
ps -ef # 全量(UNIX,含 PPID)
ps -eo pid,ppid,user,stat,pcpu,pmem,etime,cmd
ps -eo pid,cmd --sort=-pcpu | head # CPU TOP
ps -eo pid,cmd --sort=-rss | head # 内存 TOP
ps -eo pid,stat,wchan:30,cmd | awk '$2 ~ /D/' # D 状态
ps -eo stat,ppid,pid,cmd | awk '$1 ~ /^Z/' # 僵尸
ps -eLf | wc -l # 线程数
ps --ppid <PID> # 子进程
ps -p <PID> -o lstart,etime,args # 启动时间与参数
pgrep -af <name> # 查 PID + 命令行
pkill -f <pattern> # 按命令行杀(⚠️ 先 pgrep 确认)