这个命令是干啥的
ps = process status,就是"看当前有哪些进程在跑"。
刚学 Linux 的时候,找进程我就只会一招:
ps -ef | grep nginx
这招确实能用,但效率太低了。先 ps -ef 输出所有进程,再用 grep 过滤,如果机器上跑了几百个进程,输出会刷屏。而且 grep 自己也会出现在结果里(你要额外加 grep -v grep 排掉,挺烦的)。
ps 这个命令看起来简单,但它支持的选项多到能写一本书。关键是你要掌握几个高效用法,能快速找到你想要的信息。
基本用法(3分钟上手)
ps aux 是我最常用的
# 查看所有正在运行的进程
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.4 169740 13540 ? Ss 08:00 0:02 /sbin/init
root 789 0.1 1.2 523568 37512 ? Ssl 08:01 0:15 /usr/bin/dockerd
www-data 1234 0.3 2.1 456890 65432 ? S 08:05 0:45 nginx: worker process
各列含义:
- ·USER:进程所属用户
- ·PID:进程 ID
- ·%CPU:CPU 占用百分比
- ·%MEM:内存占用百分比
- ·VSZ:虚拟内存大小(KB)
- ·RSS:常驻物理内存大小(KB)
- ·TTY:关联的终端,
? 表示守护进程 - ·STAT:进程状态(S=休眠, R=运行, D=不可中断, Z=僵尸)
- ·START:启动时间
- ·TIME:累计 CPU 时间
- ·COMMAND:命令名
ps -ef 是标准输出
# 标准格式,PID 和 PPID(父进程 ID)比较清楚
ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:00 ? 00:00:02 /sbin/init
root 789 1 0 08:01 ? 00:00:15 /usr/bin/dockerd
- ·
-e:所有进程(同 -A) - ·
-f:完整格式输出,显示 PPID 等信息
只看某个用户的进程
# 只看 mysql 用户的进程
ps -u mysql
# 或者看当前用户
ps -u $(whoami)
# 用 -U 也可以
ps -U nginx
找特定进程的 PID
# 用 -C 按命令名查找,不需要 grep
ps -C nginx
PID TTY TIME CMD
1234 ? 00:00:45 nginx
1235 ? 00:00:42 nginx
对比一下 ps -ef | grep nginx 的繁琐:
# 老办法:输出多,还要排掉 grep 自身
ps -ef | grep nginx | grep -v grep
# 新办法:干净利落
ps -C nginx
进阶骚操作
--sort:按 CPU 或内存排序
# 按 CPU 占用降序排列
ps aux --sort=-%cpu
# 按内存占用降序排列
ps aux --sort=-%mem
# 先按 CPU 排,再按内存排
ps aux --sort=-%cpu,-%mem
前面加 - 是降序,不加(或加 +)是升序。
这个功能省了我很多事。以前排查 CPU 飙高的问题,我得先 ps aux 刷一堆出来,再肉眼找。现在直接排好序,头几条就是罪魁祸首。
-o:自定义输出列
嫌 ps aux 出来的列太多?自己挑想要的:
# 只看 PID、CPU%、内存%、命令
ps -e -o pid,%cpu,%mem,cmd --sort=-%cpu | head -20
# 看你想看的任何列:RSS 物理内存,VSZ 虚拟内存,USER 用户
ps -eo pid,user,rss,vsz,%cpu,%mem,comm --sort=-%mem | head -10
常用列名:pid, ppid, user, rss, vsz, %cpu, %mem, comm(命令名,不带参数), cmd(带完整参数), etime(进程已运行时间), lstart(启动时间)。
# 找运行超过 24 小时的进程
ps -eo pid,etime,cmd --sort=etime | grep -E '^ +[0-9]+-[0-9]{2}:'
树形结构:ps axjf
进程的父子关系一目了然:
# 树形进程树
ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 0:02 /sbin/init
1 789 789 789 ? -1 Ssl 0 0:15 \_ /usr/bin/dockerd
789 1298 1298 1298 ? -1 Ssl 0 0:10 \_ containerd
1 899 899 899 ? -1 Ss 0 0:00 \_ /usr/sbin/sshd
899 1500 1500 1500 ? -1 Ss 0 0:00 \_ sshd: root@pts/0
1500 1501 1501 1501 pts/0 1667 Ss 0 0:00 \_ -bash
1501 1667 1667 1501 pts/0 1667 R+ 0 0:00 \_ ps axjf
这比 pstree 还详细,能看到 PID 和用户。排查僵尸进程的时候特别有用,一眼看出哪个父进程没回收子进程。
结合 pgrep 用
# pgrep 只返回 PID 数字
pgrep -u nginx nginx
# 更简洁
pkill nginx # 直接杀进程,比 kill $(pgrep nginx) 方便
显示子线程 -Lf
# 查看进程的线程
ps -Lf 1234
# 或者看所有线程
ps -eLf
# 找到 CPU 占用高的线程
ps -e -o pid,lwp,%cpu,%mem,comm --sort=-%cpu | head -10
LWP 列显示的是线程 ID(轻量级进程)。如果某个进程有多个线程,可以看到每个线程的 CPU 占用。这排查 Java 应用或 Python GIL 相关问题时必用。
避坑指南
1. ps aux 和 ps -ef 有什么区别
其实结果差不多,但列名不太一样:
| ps aux | ps -ef | 意义 |
|---|
| %CPU | C | CPU 占用率(aux 更直观) |
| VSZ | VSZ | 一致 |
| RSS | RSS | 一致 |
| STAT | S | 进程状态 |
| START | STIME | 启动时间 |
ps aux 更常用,ps -ef 是 POSIX 标准写法,两套都认得就行。
2. 别用 ps -ef | grep 找守护进程
守护进程(daemon)通常名字里有多个实例(比如 nginx 有 master 和 worker),grep 出来一堆:
# nginx 搜索出来可能有很多条
ps -ef | grep nginx
root 1200 ... nginx: master process /usr/sbin/nginx
www 1201 ... nginx: worker process
www 1202 ... nginx: worker process
用 -C 更方便:
# 只看 nginx 进程
ps -C nginx
3. 僵尸进程怎么排查
# 找带 Z 状态的进程
ps aux | grep ' Z '
# 更准确的方法
ps -eo pid,stat,comm | grep '^ *[0-9]\+ Z'
找到僵尸进程的父进程之后,再看父进程在干什么,一般是父进程没调用 wait()。如果父进程也被卡住了,可以考虑杀父进程释放子进程。
4. ps -ef 的输出被截断的问题
ps -ef 默认命令列只显示 80 个字符,长路径会被截断:
# 用 -ww 参数取消宽度限制
ps -efww
# 或者用 auxww
ps auxww
实战场景(重点!结合真实运维场景)
场景一:找到 CPU 最高进程
服务器报警说 CPU 超过了 90%,快速登录查:
# 直奔 CPU 最高的前 5 个进程
ps aux --sort=-%cpu | head -6
# 输出格式更清晰:只看 PID、CPU%、内存%、命令名
ps -eo pid,%cpu,%mem,args --sort=-%cpu | head -10
我遇到过一次 CPU 拉满,查出来是 PHP-FPM 的某个进程卡住了。看到某个 PID 的 CPU 一直 99%,直接重启就恢复了。
场景二:排查内存泄漏
# 按内存占用排序,检查 RES 列
ps aux --sort=-%mem | head -20
# 持续监控某进程的内存变化
watch -n 2 'ps -eo pid,rss,%mem,cmd --sort=-%mem | head -10'
内存泄漏的典型表现:%MEM 和 RSS 持续增长,不会降。如果某个进程两小时从 2% 涨到 20%,那大概率泄漏了。
场景三:看某个应用开了多少进程
# Nginx worker 数量
ps -C nginx --no-headers | wc -l
# MySQL 线程数
ps -C mysqld -o nlwp --no-headers
# 某个用户跑了多少进程
ps -u deploy -o pid --no-headers | wc -l
这些数据可以写到监控脚本里,配合 Prometheus 做指标采集。
场景四:杀掉所有子进程
# 找到父进程的所有子进程
ps --ppid 1234 -o pid --no-headers
# 组合成一行杀掉
kill $(ps --ppid 1234 -o pid --no-headers)
--ppid 参数按父进程 ID 过滤,非常实用。
场景五:定位 Java 应用线程问题
# 找到 Java 进程的 PID
ps -C java -o pid --no-headers
# 查看这个 Java 进程的所有线程
ps -Lf $(ps -C java -o pid --no-headers)
# 把 CPU 最高的线程转成十六进制(用于 jstack 匹配)
ps -eo pid,lwp,%cpu,comm --sort=-%cpu | head -5
# 线程 ID 转 16 进制
printf '%x\n' 12345
然后用 jstack 找到对应的线程栈,就知道代码卡在哪了。
今日作业(一道小题目)
题目:你的服务器突然变慢了,登录后发现 CPU 用了 98%,但不知道是哪个进程搞的。
要求:
1. 用一条 ps 命令找到 CPU 占用最高的 3 个进程
2. 输出只显示 PID、CPU 百分比、内存百分比、命令名
3. 按 CPU 降序排列
4. 同时再写一条命令,找到内存占用最高的 3 个进程(按内存降序)
写出这两条命令,并解释每条输出会看到什么。不限速。