1. 一行命令背后的系统体检术在服务端排查问题、写监控脚本、或者纯粹想看看机器上到底什么程序在“偷跑”的时候ps aux --sort-%cpu | head这串命令几乎是每个运维和开发脑子里第一个蹦出来的东西。它很短短到一眼就能扫完但它又很密密到把进程查询、状态过滤、性能排序、输出裁剪这几件事全塞进了一次管道操作里。说白了这一行命令干的就是一件事把当前系统里所有进程按 CPU 占用率从高到低排队然后只把最前面的那一小撮默认10个亮给你看。这有点像你在火锅店后厨大喊一声“谁在摸鱼”然后管事儿的把所有人按工作量排了个序指着最忙的那几个说“就他们”。你不需要看后厨所有人你只需要知道谁最吃CPU、谁需要被处理。我自己在这行里摸爬滚打这么多年真正让我觉得“得心应手”的不是背了多少命令而是把一条命令的每个零件都拆开、弄明白每一段在干什么。这就像庖丁解牛刀刀有理游刃有余。这篇就把ps aux --sort-%cpu | head从头到尾、从参数到管道、从输出字段到排错思路一块一块拆给你看。适合刚接触 Linux 服务管理的新手也适合那些天天在用却没认真琢磨过每个字段含义的“熟练工”。2. ps 命令的两个“派系”别再把 aux 当成 a、u、x 的随意组合2.1 为什么是“aux”而不是“-aux”很多人第一次接触这条命令都会有个疑惑ps的用法里明明写的是ps -ef或者ps aux为什么有的带横杠、有的不带这背后其实是 Unix 历史上两套语法体系并存留下的“遗产”。带横杠的写法比如ps -ef是 Unix 风格SysV 风格参数以-开头不带横杠的写法比如ps aux是 BSD 风格参数就是裸的字母。Linux 的ps实现来自 procps-ng 项目两种都兼容这也是为什么你有时候看到ps aux有时候看到ps -ef两者都能跑。那a、u、x到底各是什么含义a显示所有终端tty下的进程包括其他用户的进程。注意这里有个隐含条件——a选项本身会筛选“有控制终端”的进程但加上x之后就不一样了。u以“用户导向”的格式展示详细信息也就是会多出来USER、%CPU、%MEM、VSZ、RSS、START这些列。如果只写ps a或者ps x列会少很多。x包含没有控制终端的进程。什么叫没有控制终端后台守护进程、开机自启服务、脱离终端的程序都属于这一类。你如果只敲ps a那些系统服务基本全被过滤掉了。所以aux合在一起的含义就是显示所有用户的、所有终端和非终端的进程并且用用户友好的详细格式输出。这是排查系统问题时最常用的“全量进程视图”。2.2 千万别写成“ps -aux”这是个经典误区我见过不止一个新手在博客、教程里写ps -aux然后跑出来一堆奇怪的警告甚至结果都不对。原因是-aux在 Linux 的ps里会被解析成-a -u -x而-u在这里被解释成了“按用户 ID 显示”不是 BSD 风格的u格式两者输出的列格式完全不同。实际跑一下你会看到ps -aux经常输出类似Warning: bad ps syntax, perhaps a bogus -的提示而且列头会变成USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND这样的 SysV 风格混杂格式。虽然看起来和ps aux差不多但它其实是把选项组合猜错了。注意在 Linux 上标准写法就是不带横杠的ps aux。这是一条老生常谈但值得反复强调的规则。2.3 快速对比ps aux 和 ps -ef 怎么选评论两句我用过的经验对比解决很多人的选择困难对比维度ps auxps -ef语法流派BSD 风格无横杠SysV 风格带横杠输出格式带 %CPU、%MEM、VSZ、RSS人性化带 UID、PID、PPID、C、STIME、TIME典型用途排查 CPU/内存占用、看资源消耗看父子进程关系、看进程树、脚本解析上手难度字段直观适合人看字段简洁适合程序读ps aux对人更友好因为它直接告诉你百分比的 CPU 和内存占用ps -ef的好处在于有PPID父进程 ID适合用来梳理进程之间的血缘关系。我自己平时看资源占用用ps aux查父子关系用ps -ef两者各司其职。3. --sort-%cpu排序参数里的“隐藏发动机”3.1 排序选项的完整语法--sort是 GNUps提供的一个长选项用来指定输出按哪个字段排序。它支持多种排序键常见的有%cpu—— 按 CPU 占用率排序%mem—— 按内存占用率排序rss—— 按常驻内存大小排序vsz—— 按虚拟内存大小排序pid—— 按进程号排序time—— 按累计 CPU 时间排序comm—— 按可执行文件名排序关键点在于字段前的符号加号可以省略代表升序减号代表降序。比如--sort-%cpu就是“按 CPU 占用率从高到低排”--sortrss等价于--sortrss是“按内存占用从小到大排”。你可能好奇这个排序是在ps内部做的还是靠外部工具做的答案是ps内部做了排序再输出。它把所有进程快照抓取一遍然后根据你指定的键值在内存里排好序最后按顺序打印出来。所以这条命令天然适合和head搭配因为head只需要前几行ps已经把最想看的排到了最前面。3.2 为什么用 %cpu 而不是 time这是个很容易踩的认知盲区。%CPU和TIME是两回事%CPU表示进程在一段时间内占用 CPU 的百分比。这个值是ps根据进程的累计 CPU 时间和总运行时间推算出来的是一个“瞬时/近期”的模糊估计。TIME表示进程自启动以来累计消耗的 CPU 时间单位通常是分钟:秒。它是只增不减的“历史账本”。举个例子一个进程跑了三个月累计 CPU 时间很长TIME 很大但最近几天基本在睡觉%CPU 几乎为 0。如果你按time排序它会排在最前面但这并不代表它现在是个问题如果你按%cpu排序它就会沉到后面去。排查“当前谁在咬 CPU”必须用 %cpu排查“谁累计消耗 CPU 最多”才用 time。这俩目标不一样选错排序键就会得出错误结论。3.3 内核态和用户态的隐含信息%CPU反映的是这个进程占用的 CPU 时间片比例它既包括用户态执行程序自身的代码也包括内核态进程发起的系统调用。所以当你看到一个进程 %CPU 接近 100%别急着说“它在疯狂计算”——它也可能是在疯狂做系统调用比如频繁读写文件、网络请求、内存分配。想让区分更细可以用ps -o pid,pcpu,time,comm配合top的S模式来看但日常排查其实不需要分这么细先把“谁在占用”揪出来再说。实操心得在单核机器上所有进程的 %CPU 加起来理论上最高是 100%在多核机器上这个上限是 核心数 × 100%。所以如果你看到某个进程 %CPU 是 350%不要惊讶它只是吃满了将近4个核而已。我这几年见过不少新手把多核进程当成异常值其实它可能只是多线程并行任务正常发挥。4. 管道和 head把“全量名单”裁剪成“前十榜单”4.1 管道符 | 的本质是数据接力在ps aux --sort-%cpu | head里|把ps的标准输出stdout接到了head的标准输入stdin。ps负责把排序后的进程列表一行行吐出来head负责只读前 N 行剩下的数据直接丢弃绝不浪费时间去消费。这有点像自动售货机出饮料ps是那个把所有饮料一瓶瓶推出来的装置head是只拿走前面前10瓶的人后面的饮料没人拿也不会继续倒出来实际上ps会停止接收head已经关闭的管道这里就涉及 SIGPIPE 机制了。具体来说当head读完前10行就退出时管道关闭ps继续写数据就会收到一个 SIGPIPE 信号默认动作是终止进程。所以这个组合不仅在输出上做了裁剪在执行上也是“按需生产”不会傻乎乎地把全部几千行进程列表都格式化完再交付。4.2 head 默认显示几行head默认输出前 10 行但注意ps aux输出里第一行是表头不是进程数据。所以实际你看到的进程数量是 9 个不是 10 个。这个问题经常被忽略很多人以为head给了 10 个进程其实是 9 个。如果你就是想看前 20 个进程可以用head -n 20或者写成head -20。我习惯用-n因为可读性好且不会和-20这种数字混淆。4.3 管道组合的常见变体管道的美妙之处在于可以随意插接别的工具只要你想清楚“上一步输出什么、下一步需要什么”。我的几个常用变体# 按内存占用排序取前15名 ps aux --sort-%mem | head -n 15 # 只看某个用户的进程并按CPU排序 ps aux --sort-%cpu | grep username # 动态刷新每2秒看一次CPU最高进程 watch -n 2 ps aux --sort-%cpu | head -n 12 # 彻底去掉表头纯数据方便脚本处理 ps aux --sort-%cpu | awk NR1 {print $2, $3, $11} | head -n 10watch那个组合我特别推荐它能把静态的一次性命令变成“会刷新的仪表盘”虽然不如top全面但在只想盯住 CPU Top 榜的场景下非常轻量好用。5. 输出字段逐个拆解看懂每一列的潜台词5.1 从 USER 到 COMMAND 的一张速查表ps aux的默认输出列是固定的USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND。下面这张表是我压箱底的解释字段含义结合排查经验一起讲字段含义实战解读USER启动进程的用户如果是 root说明该进程有较高权限排查时需要格外小心PID进程 ID唯一定位进程的编号kill 指令直接用它%CPUCPU 占用百分比多核下可能超过100是排序主角%MEM物理内存占用百分比反映该进程占系统总内存的比例排查内存压力看它VSZ虚拟内存大小KB进程“以为”自己占用的内存含未实际分配的虚拟部分RSS常驻物理内存大小KB真正占用的物理内存看内存应该以 RSS 为准TTY关联终端为?表示无终端后台服务/守护进程STAT进程状态D/R/S/T/Z 等具体解读见下文START启动时间帮助判断是不是“活了很久的老进程”TIME累计 CPU 时间历史累计值不代表当前活跃度COMMAND完整命令行命令行参数也在里面方便确认是哪个项目5.2 VSZ 和 RSS虚拟内存与物理内存的差距我见过不少人在看内存占用时盯着 VSZ 看以为它是内存占用的真实反映这是个很常见的误解。VSZ 是虚拟内存大小它包括了进程映射的所有地址空间——包括那些“申请了但还没碰过的内存页”。举个例子JVM 启动时往往会预留一整块大内存区域作为堆空间VSZ 可能显示几十个 GB但 RSS 可能只有几个 GB因为大部分页还没被实际写入。真正吃物理内存的是 RSS。排查内存问题比如 OOM、内存泄漏、内存不足一定是看 RSS 和 %MEM。VSZ 的唯一价值在于判断程序是否存在“虚拟地址空间耗尽”这类极端问题日常基本用不上。5.3 STAT 状态码里的字母游戏STAT 列看起来只是一个字母串但它蕴含的信息量很大。常见的状态码含义R正在运行RunningS可中断睡眠Sleeping等待事件D不可中断睡眠通常在等待 I/O俗称 D 状态T停止Stopped比如被 CtrlZ 挂起Z僵尸进程Zombie父进程还没回收子进程残留的 PCBI空闲内核线程Idle另外还会带上一些附加标识比如代表高优先级N代表低优先级nicel代表多线程s代表是会话首进程。比如你看到Rsl说明这是一个会话首进程、多线程、当前正在运行。实操心得D 状态是排查故障的重点关注对象。如果大量进程卡在 D 状态通常是磁盘 I/O 或 NFS 卡死了。这时候ps aux看不出根因得配合iotop、dmesg查看内核日志才能定位。Z 状态同理一两个僵尸进程还好成批出现说明某个父进程出问题了没有正常调用 wait 系统调用回收子进程。5.4 TIME 列千万不要当成当前 CPU 占用前面已经提过 TIME 是累计值这里再举一个具体例子。假设你有一个数据库进程TIME 显示 124:56这说明它自启动以来累计消耗了约 125 分钟的 CPU 时间。如果它启动了一个月平均下来每天不到 5 分钟一点都不高但如果你昨晚启动了一个任务才过了 2 小时TIME 就已经 124 分钟了那说明它几乎把单核 CPU 全占了。所以 TIME 列要结合 START 列一起看累计时间除以运行总时长才是这个进程的平均 CPU 占用率。这层换算关系理解了排查长期运行的异常进程会快很多。6. 三个实战场景从“会敲命令”到“会查问题”6.1 场景一网站变慢先看谁在抢 CPU假设线上环境突然响应迟缓登到服务器第一件事就是用ps aux --sort-%cpu | head -n 15。如果看到某个 Java 应用进程的 %CPU 高达 300%而平时它只有 50% 左右那就说明它内部八成在做大量计算或是在处理一场流量洪峰。下一步我不会直接 kill而是先top -Hp PID去看这个进程内部的线程-H 显示线程找到具体吃 CPU 的线程 ID再把它转成十六进制去抓线程栈。整个链路追查下来问题基本都能定位到某个具体的线程和业务逻辑。没有第一行命令的“快速初筛”后面的所有操作都没有方向。6.2 场景二内存吃紧换一个排序键如果机器明明 CPU 不高但频繁触发 OOM 或者 swap 大量写入说明内存才是瓶颈。这时候排序键要从%cpu换成%mem命令变成ps aux --sort-%mem | head -n 20你会看到一波“内存大户”排名。很多场景下排名第一的往往是某个配置了超大缓冲的中间件或者是有内存泄漏的长期运行进程。观察它的 RSS 是否持续增长是判断“暴涨但正常”还是“泄漏有问题”的关键。我习惯连续执行几次间隔 10 到 30 秒看 RSS 有没有只升不降的趋势。如果稳定涨基本可以确认是泄漏。6.3 场景三定位某类进程结合 grep 精准过滤有时我们不需要全量 Top只想看某个服务的进程整体占了多少资源。比如想知道所有 Nginx 工作进程的情况ps aux | grep nginx | grep -v grep注意那个grep -v grep的作用它把grep nginx这个查询进程本身也出现在结果里的情况排掉了。如果不加它你会在输出里看到一行grep --colorauto nginx那只是查询行为本身不是真实业务进程会干扰判断。命令里为什么要保留--sort-%cpu因为这样可以在同类型进程里快速找到最“突出”的那个比如某个 Nginx worker 的 CPU 占用明显高于其他 worker说明这个 worker 正在处理高负载请求可能是热点流量打到了某一两个 worker 上。7. 常见坑与排查技巧实录7.1 坑一%CPU 是平均值不是瞬时值这是ps最容易误导人的地方。ps计算 %CPU 的公式大致是进程累计 CPU 时间变化量 / 两次采样之间的墙钟时间。也就是说它是从进程启动或某个基准点开始算的“平均占用率”不是此刻的一瞬间占用率。如果你用ps和top对比同一个进程的 %CPU往往会发现二者数值不一致——因为top默认显示的是最近 3 秒内的瞬时刷新值。所以想要“准”的当前占用率推荐top -b -n 1或者pidstat这类工具。ps的 %CPU 更适合做“趋势判断”而不是“精确测量”。7.2 坑二head 把表头也算进去了前文提过head默认取前 10 行而ps aux的第一行是表头。所以真实拿到的进程数量只有 9 个。这在自动化脚本里尤其危险如果脚本假设“前 10 行都是进程”那第一行解析就会出错得到USER这个字符串而不是 PID。写脚本时要记得awk NR1或者tail -n 2跳过表头。7.3 坑三排序键写错导致命令直接报错--sort的排序键是大小写敏感的比如--sort-PID会报错因为正确的键是小写的pid。同时一些不支持的字段名也会让 ps 返回错误。为了避免这种低级问题建议敲完命令先跑一次看看有没有报错提示。7.4 坑四你看到的 COMMAND 可能不完整ps aux的 COMMAND 列理论上会显示完整命令行但当命令行超长时会被截断。这也会带来排查障碍——当你想区分两个看起来相似但参数不同的进程时截断的 COMMAND 会让它们看起来一模一样。这时候可以用ps -eo pid,ppid,user,cmd --sort-%cpu | head把列换成cmd完整命令行或者用-ww参数取消宽度限制ps auxww --sort-%cpu | head -n 12ww告诉 ps 不要截断命令行这样即使参数很长也能完整显示出来。我自己在查 Java 启动参数和 Python 脚本路径时经常靠它救命。7.5 坑五容器环境下的进程视角如果你在 Docker 容器里执行ps aux看到的结果是宿主机的全部进程还是容器内进程取决于容器 init 进程和 ps 工具的行为。现代容器大多共享宿主内核进程表本质上是一张全系统的进程表但 PID namespace 会做隔离——容器里只能看到自己命名空间内的进程。如果你发现自己容器里用ps aux看到了一堆宿主机的进程说明该容器的 PID namespace 没隔离比如用了--pidhost或者你直接在宿主机看了。排查容器问题时要先弄清楚这个前提否则会把别家服务的进程误认成自己的。8. 进阶玩法按需定制输出格式彻底摆脱默认范本8.1 用 -o 精确选取自己关心的列ps aux的默认列已经很好用但有时候我们只想要 PID、CPU 占用和命令不想看 VSZ、RSS 这些干扰项。-o选项就是为此设计的ps -eo pid,user,pcpu,pmem,rss,comm,args --sort-pcpu | head这里-e等价于aux里的“所有进程”-o后面跟逗号分隔的字段列表。字段名也有讲究pcpu、pmem是百分比rss是 KB 数comm是进程名args是完整命令行。用-o自定义的好处有两个一是输出更干净、更聚焦二是字段顺序完全由你控制写脚本解析时非常友好。8.2 聚合统计多个同类进程合并看有时候一个服务会启动很多 worker你逐个进程看意义不大更关心的是“这个服务的总 CPU 占用”。这时候ps可以和awk联合作业ps aux | awk NR1 $11nginx {cpu$3; mem$4} END {print cpu:, cpu, mem:, mem}这个命令把所有进程名是 nginx 的 CPU 百分比累加、内存百分比累加最后输出总和。注意$11字段是 COMMAND 的第一个词进程名匹配用的是字符串相等如果你要模糊匹配可以用index($11, nginx)之类的写法。内存百分比和 CPU 百分比都可以这样聚合非常实用。8.3 与 top/htop 的配合使用ps aux --sort-%cpu | head的快照式输出适合“拍一张照片”看现状top的交互式界面适合“持续观察动态变化”htop的彩色友好界面和树形展示适合人肉排查。我自己的习惯是初筛用ps因为轻量、快捷、可脚本化深入用top或htop看刷新趋势、按 P/M/T 键切换排序、按 F 添加更多字段长期追踪、后台记录用pidstat或者atop甚至直接采集/proc数据做监控系统没有哪个工具是万能的但ps aux --sort-%cpu | head这一行命令永远是那个“最顺手的第一把刀”。9. 写在最后的几点个人心得命令本身并不复杂复杂的是你脑子里有没有一套清晰的排查框架。我这些年用下来最大的体会就是任何一条命令都值得拆开看。拆懂了ps的 aux 和 sort你再看top的交互键、htop的样式、pidstat的输出都会觉得似曾相识——因为它们的底层字段和含义都是同一套体系。还有一个小技巧值得分享在写自动化脚本时别直接拿ps aux的 %CPU 字段做精确到小数点后一位的阈值判断。它本身是个估算值受采样时机影响很大。要做严谨的监控告警用pidstat或者从/proc/pid/stat里自己计算两次采样的差值才是靠谱的做法。最后想说的是排查问题的心态比命令熟练度更重要。遇到系统异常先稳住按“CPU → 内存 → I/O → 网络 → 内核日志”的顺序一层层查ps aux --sort-%cpu | head只是这条链路上的第一步。把它练熟了后面的每一步都会顺很多。
阅读完成 · 觉得有帮助?