那天夜里两点多,线上两台应用服务器同时告警,接口响应时间从几十毫秒涨到快十秒。登录机器后我做的第一件事,就是敲下top看整体负载,再用ps追到具体进程,最后用free确认内存水位。这三条命令我从入行用到现在,几乎每天都会和它们打交道,但直到今天,依然能在一些细节上发现新的东西。如果你是刚接触Linux的运维、后端开发,或者准备面试系统管理岗位,这篇文章应该能帮你把top、ps、free这几个最基础又最容易用出花样的命令,从“会敲”提升到“会用”的层次。
标题里这三个命令分别解决三个不同层面的问题:实时监控、静态查看、内存水位确认。它们之间不是替代关系,而是配合关系。理解清楚各自的使用场景、输出含义和常见误区,才能真正在排障时做到心里有数。
1. 服务器卡顿的第一现场:我为什么离不开这三个命令
很多人遇到服务器卡顿,第一反应是直接看监控面板,但监控面板往往只有曲线,没有进程维度的实时数据。登录服务器后,top就是那个让你一眼看到系统全貌的命令。
1.1 从一次线上故障说起
那次故障的表现很典型:服务无响应,但物理机没宕。我先敲top,看到load average已经飙到30多,CPU的us和wa两项指标居高不下。接着用ps aux --sort=-%cpu定位到具体PID,发现是某个Java进程的GC线程在疯狂占用CPU。最后用free -h确认物理内存还够,但Swap已经被换出不少。整个过程加起来不到五分钟,三个命令配合下来,问题就锁定了。
如果你没有养成“先top、再ps、必要时free”的排查习惯,很可能在监控面板上绕来绕去,甚至在业务日志里翻半天。这就是这三个命令的核心价值:它们构成了一个从整体到局部、从现象到原因的排查链条。
1.2 命令之间的分工逻辑
top是动态的,它每隔几秒刷新一次,告诉你现在的CPU、内存、负载在什么水平;ps是静态的,它拍一张当前进程状态的快照,让你不依赖刷新就能精确查找某个进程;free则专门看内存,它把内存的分配逻辑讲得很清楚,尤其是buffer和cache的区别,很多人在这里栽过跟头。
把这三个命令放在一起理解,你会形成一套相对完整的系统状态评估方法。下面我把每个命令单独拆开来讲,配合实际输出和常见参数,尽量讲到“看完就能用”的程度。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. top实战:不再只看那一排“僵尸数据”,学会判断真问题和假负载
top可能是Linux里被用得最多、也被误解最多的命令。很多人每次上来就盯着那一串CPU百分比看,但top的前五行统计信息里藏着大量判断依据,交互快捷键更是能帮你快速找出“真凶”。
2.1 top输出里每行到底在说什么
为了把问题讲清楚,我先贴一段典型的top输出:
code复制top - 14:23:45 up 120 days, 3:15, 2 users, load average: 8.12, 6.34, 5.02
Tasks: 210 total, 1 running, 209 sleeping, 0 stopped, 0 zombie
%Cpu(s): 65.3 us, 12.1 sy, 0.0 ni, 18.4 id, 3.2 wa, 0.0 hi, 1.0 si, 0.0 st
MiB Mem : 32000.0 total, 4200.5 free, 16000.3 used, 11799.2 buff/cache
MiB Swap: 8192.0 total, 6100.0 free, 2092.0 used. 15200.0 avail Mem
第一行除了时间和机器运行时长,最关键的是load average,也就是后面那三个数。这三个数分别代表1分钟、5分钟、15分钟的平均负载。很多教程说这个值超过1就危险,其实不完全对。关键要看你的机器有多少个CPU核心。比如nproc返回8,那负载8意味着CPU刚好被填满,超过8才说明任务在排队。上面例子中1分钟负载8.12,如果机器是4核,那已经超载一倍。负载高不一定全是坏事,但要警惕持续走高,因为那意味着任务积压。
第二行的Tasks里有zombie这个老熟人。看到僵尸进程不用太紧张,只要数量不多、不是持续增长,通常由父进程回收失败引起。但如果僵尸进程大量堆积,你就要去查对应的父进程是否异常了。
第三行%Cpu(s)里的字段,我重点说几个容易被忽略的:us是用户态CPU占用,sy是内核态占用,wa是等待I/O完成的占比,st是被虚拟机管理程序偷走的时间。如果你跑在云主机上,st过高说明物理机的CPU资源被其他虚拟机争抢,这时候你优化程序也没用,得考虑换实例或者迁移。wa高则大概率是磁盘I/O瓶颈,比如慢查询、日志写入过频、Swap颠簸。
第四行和第五行是内存和交换分区信息。注意buff/cache那一项,在free那里我会重点讲,top里的buff/cache同样表示内核用作缓存的内存,这部分内存可以随时让出来给应用程序用。
2.2 交互快捷键:只靠看是低效的,要会“动”
top最强大的地方不是它默认展示的内容,而是运行期间能通过按键直接切换视图。我常用的几个:
P:按CPU占用排序,定位谁在烧CPUM:按内存占用排序,定位谁在吃内存k:输入PID后可以直接发信号杀进程,省得再开一个终端敲killr:调整进程优先级(nice值)1:展示/折叠每个CPU核心的使用情况,多核机器上非常有用,能看到负载是否均衡f:进入字段管理界面,勾选你关心的列,比如进程的启动时间、线程数、运行时长H:切换线程视图,排查“一个进程高CPU但不知道是哪个线程”的问题时必用
举一个最典型的例子:Java进程CPU飙高。先按P找到进程PID,然后按H,你会看到这个进程下面具体哪个线程在耗CPU。记下线程PID,把它转成十六进制(printf "%x\n" PID),再用jstack去线程栈里搜这个十六进制编号,就能定位到是哪段代码的问题。整套流程我用了无数次,是Java服务排障的标准动作。没有top的线程视图,这个工作会麻烦得多。
2.3 top的常用命令行参数
除了交互快捷键,top本身也支持很多有用的参数:
top -d 1:把刷新间隔改成1秒,默认通常是3秒。排查偶发CPU尖刺时,3秒可能错过现场,1秒更合适。top -p PID:只看指定的进程,适合你心里已经有了目标PID,不想被其他进程干扰。top -u username:只看某个用户的进程,多用户共用机器时很实用。top -H -p PID:以线程模式查看指定进程,等价于运行后按H再搜索PID。top -b -n 1:批处理模式,只输出一次结果。适合写脚本抓取系统状态,或者配合head截取前几行。
我在脚本里最常用的是top -b -n 1 | head -20,抓取一次当前系统状态,然后丢给监控通知。另外提一点,top是实时刷新的,如果你在SSH会话里跑长时间刷新,断开连接后进程可能继续存在,最好配合-b模式或者timeout命令限制运行时间。
2.4 看懂伪命题:多核与CPU百分比
还有一个常见误区,就是看到某进程CPU占用显示100%就以为机器完蛋了。如果机器有4个核心,单进程跑满一个核,显示就是100%,但实际整体CPU只用了25%。反之,如果进程是线程密集型的,单进程CPU可以累加到400%甚至更高,那是它并行占用了多个核心。判断机器是否“卡”要回到load average和总CPU占用,而不是单个进程的百分比。
3. ps的精准查询:从“大海捞针”到一行命令锁定目标进程
top适合看整体、找异常,但如果我告诉你“去查一下那个PID是3387的进程是不是还在”,用top就不太方便了。这时候ps才是正确的工具。ps打印的是执行瞬间的进程状态快照,不会持续刷新,所以特别适合脚本和精确查找。
3.1 两种风格:ps aux与ps -ef的区别
ps命令的历史包袱比较重,支持多种选项风格,新手最容易困惑的就是aux和-ef的区别。
ps aux里的a表示显示所有用户的进程,u表示以用户为主的格式输出,x表示也显示没有终端控制的进程。ps -ef里的-e代表显示所有进程,-f代表完整格式。两者列出的字段不完全一样:
ps aux输出:USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDps -ef输出:UID PID PPID C STIME TTY TIME CMD
ps aux的%CPU和%MEM是排障时最直观的列,而ps -ef里的PPID(父进程ID)对梳理进程树更友好。实际工作中我不太纠结用哪个,谁顺手用谁。但脚本里如果要排序和过滤,ps aux更常用。
3.2 ps aux输出字段逐个过一遍
拿一行典型的ps aux输出来看:
code复制root 1234 2.3 1.2 3167540 392920 ? Ssl Mar12 45:20 java -jar app.jar
USER:进程属于哪个用户。看到root权限运行的业务进程要谨慎,权限过大。PID:进程ID,排障的锚点。%CPU:进程到目前累计CPU使用率,注意它不是实时的,是平均值。如果想看瞬时值,依然推荐top。%MEM:进程占用物理内存的百分比。VSZ:虚拟内存大小,包括没在物理内存里的部分。这个值通常很大,不用慌。RSS:常驻内存大小,进程实际占用的物理内存量,这才是你评估内存使用时主要看的指标。TTY:进程关联的终端。?表示与终端无关,通常是守护进程或内核线程。STAT:进程状态。S是睡眠,R是运行,Z是僵尸,T是停止,l表示多线程,+表示在前台进程组。组合字符还能看到更多信息。START:进程启动时间。TIME:进程累计占用CPU的时间。这个值非常大时,说明进程已经运行了很久且持续吃CPU。COMMAND:启动进程的命令行。注意看这里,很多时候你排查恶意进程或者识别业务进程身份,靠的就是这一列。
3.3 我常用的ps组合命令
我把这些年用得最多的几条ps命令列出来,可以直接抄:
ps aux --sort=-%cpu | head -20:按CPU占用降序,取前20条。定位高CPU进程第一选择。ps aux --sort=-%mem | head -20:按内存占用降序,取前20条。排查内存泄漏时常用。ps -ef | grep java:查所有Java相关进程。grep过滤时建议用grep java | grep -v grep,避免把grep自己匹配进去。ps -eo pid,ppid,%cpu,%mem,cmd --sort=-%cpu | head -20:用-e加-o自定义输出列,比aux更灵活。cmd对应命令列,%cpu可以直接参与排序。ps -L -p PID:查看指定进程的所有线程。效果类似top按H,但在脚本里更方便。ps -ef --forest:以树形结构显示父子进程关系,一眼看出谁启动了谁。排查守护进程和启动器问题特别好用。
3.4 ps的查看进程小技巧:围绕PID做文章
定位到PID只是第一步,很多衍生操作都以PID为锚点:
ls -l /proc/PID/cwd:看进程的当前工作目录,能帮你确认进程是不是在预期目录下启动的。cat /proc/PID/environment:看进程的环境变量,有些配置问题能在这里找到线索。cat /proc/PID/status:看进程的详细状态,包括内存、线程数、状态标志。pstree -p PID:用树状方式展示PID所在的整棵进程树。
ps和/proc文件系统是深度绑定的,/proc/PID下面的文件就是进程的“档案室”。我经常把ps查到PID,然后去/proc/PID下面确认更多细节,这个组合在面试里也经常被问到。
3.5 识别进程状态里那些“怪样子”
STAT列里的字母组合,看起来像乱码,其实每个字母都有含义。我遇到过不止一次,同事看着Z说“这进程是不是坏了”,其实只是它等待父进程收尸而已。下面是我踩坑总结的常见形态:
S:可中断睡眠,进程正在等某个事件。大多数业务进程都处于这个状态。R:运行中或等待运行。CPU满时你会看到很多R进程排队。D:不可中断睡眠,通常是在等磁盘I/O。这个状态处理不掉,只能等I/O完成,如果大量进程卡在D,基本可以断定磁盘坏了或者存储挂了。Z:僵尸状态。已经退出但没被父进程回收。偶尔一两个没关系,数量暴涨就要查父进程。l(小写L):多线程进程。Java进程基本都会有这个标记。
顺带说一句,很多恶意程序或者挖矿程序为了隐蔽,进程名会伪装成kworker、ksoftirqd这类内核线程名。区分方法很简单:看ps输出的CMD列,内核线程通常显示在中括号里,比如[kworker/0:1],而恶意程序不会用中括号包裹。
4. free里的内存“障眼法”:buffer与cache对剩余内存的影响
free是这三个命令里输出最简单、最容易被误读的一个。我见过不少有几年经验的人,看到free里free列数值很小就开始加内存,其实完全是误解。Linux对内存的管理策略决定了“空闲内存”会被尽可能用掉,但不是说你的机器内存不够了。
4.1 free输出的完整结构拆解
先看一段典型的free -m输出(-m表示以MB为单位):
code复制 total used free shared buff/cache available
Mem: 32000 9000 3500 300 19500 22000
Swap: 8192 1000 7192
第二行Mem里几个关键字段:
total:物理内存总量。used:被认为已使用的内存。free:完全未被使用的内存。shared:多个进程共享的内存,通常来自tmpfs这类临时文件系统。buff/cache:被内核用作缓冲区(buffer)和页缓存(cache)的内存。available:估算的、可用于启动新程序的可用内存。这个值才是你真正看重的水位指标。
第五列buff/cache是很多人误解的根源。Linux会尽量把空闲内存用作缓存,加快磁盘读写和文件访问,所以free列数值小不代表内存紧张。真正要看的是available这一列,它已经扣除了内核保留和不可回收的缓存,表示在不触发大量Swap的情况下,还能给新进程分配多少内存。
4.2 buffer和cache到底有什么区别
简单区分:
- buffer(缓冲):用于块设备的缓冲,比如直接读写磁盘时的数据暂存区。它针对的是“块设备”。
- cache(缓存):用于文件系统的页缓存,把读过的文件内容缓存在内存里,减少磁盘I/O。它针对的是“文件”。
举个例子:你用dd写一个块设备,中间数据会经过buffer;你用cat读一个大文件,文件内容会被放进cache。在现代Linux内核中,两者在管理上的界限已经比较模糊,统一显示在buff/cache列,但理解底层逻辑还是必要的。
为什么很多教程说“cache不用管,会自动释放”?因为内核在内存压力增大时,会优先回收cache来满足新分配需求。所以buff/cache占用量高不代表内存不够,反而说明你的内存被充分利用了。只有当你需要的内存超过物理内存,不得不使用Swap时,才说明真的不够了。
4.3 什么时候说明内存真的不够用了
判断内存是否紧张,我有一个习惯性的顺序:
- 看
available占total的比例。如果低于20%,要警惕。 - 看Swap的
used是否持续增长。Swap被大量使用是内存不足的明确信号。 - 观察
Si和So,这是vmstat输出里的swap in/out指标。如果持续不为0,说明系统在不断换页,性能会受到明显影响。 - 结合
top看是否有进程占用了超大RSS,确认是不是有内存泄漏。
如果available充足,即使free列只有几百MB,也不用急着加内存。把内存拿来当缓存用,正是Linux的设计意图。
4.4 free的常用参数和扩展技巧
free的参数不多,但有几个很实用:
free -h:以人类可读的格式输出(G、M),日常查看最推荐。free -m:以MB显示,脚本统计时更精确。free -g:以GB显示,适合看大内存机器。free -s 3:每3秒刷新一次,类似持续监控。配合-c 5可以只刷5次然后退出,适合脚本采集数据。free -w:把buffer和cache拆开显示,分得更清楚,想确认是文件缓存还是块设备缓存时用。
看自己应该用哪个参数?日常随手用free -h,脚本里用free -m(因为MB是整数,好做阈值判断),需要持续观察用free -s 3 -c 10。
4.5 和top里面Mem的区别
top第一屏显示的Mem和free -m数据来源一致,都是/proc/meminfo。区别只是展示方式。top里没有available列,所以更容易让不熟悉的人误判内存紧张。遇到这种情况,我一般会再敲free -h确认一下,而不是只看top那一屏。
5. 排查问题的完整链路:top、ps、free协同使用的标准动作
三个命令单独讲完了,但它们在一起才构成完整的排障闭环。这一节我模拟几个真实场景,把命令的配合方式和分析思路串起来。
5.1 场景一:CPU整体飙高,不知道是哪个进程的锅
标准动作:
code复制# 1. 看整体负载和CPU占比分布
top -d 1
# 2. 按CPU排序,看到具体的PID
# 按 P 键,记下CPU最高的几个PID
# 3. 用ps确认详细信息
ps -fp PID1,PID2,PID3
# 4. 如果是Java应用,进一步查线程
top -H -p PID
这四步下来,你能从“整体卡顿”定位到“哪个进程的哪个线程在烧CPU”。如果没有top的排序,直接ps aux也能看到,但刷新频率和可操作性不如top,尤其在现场持续很短的情况下,top的实时性更有优势。
5.2 场景二:内存告警,但是不知道谁在吃内存
标准动作:
code复制# 1. 先看总内存水位
free -h
# 2. 如果available很低,看Swap是不是也被使用了
free -m | awk '/Swap/ {print $3}'
# 3. 按内存占用排序找进程
ps aux --sort=-%mem | head -20
# 4. 确认进程是否异常增长
ps -o pid,rss,vsz,cmd -p PID
注意第4步的RSS是当前值,要判断是否泄漏,需要隔几分钟抓一次RSS做对比。比如:
code复制for i in {1..5}; do ps -o pid,rss,cmd -p PID | tail -1 >> rss_history.txt; sleep 60; done
如果RSS只增不减,内存泄漏的概率就非常大了。
5.3 场景三:服务假死,既不高CPU也不吃内存,但就是没有响应
这种问题比较隐蔽,我的排查顺序是:
code复制# 1. 先看进程状态是否异常
ps aux | grep java
# 2. 看进程有没有卡在D状态
top -b -n 1 | grep PID
# 3. 看等待CPU的线程数量
top -b -n 1 | grep -c " R "
# 4. 结合free看是不是内存紧张,导致频繁换页
free -h
vmstat -1
进程卡在D状态常见于磁盘故障、网络存储断开、NFS挂载失联。vmstat里的wa和si/so能辅助判断是不是I/O问题。如果wa很高,连登录都慢,那基本就是存储层的锅。
5.4 我的个人习惯:做一个快速巡检别名
经常敲这些命令后,我在个人配置里加了几个别名,一键输出关键信息:
bash复制alias topcpu='top -b -n 1 -o %CPU | head -25'
alias topmem='top -b -n 1 -o %MEM | head -25'
alias pstop='ps aux --sort=-%cpu | head -20'
alias meminfo='free -h && echo "---" && cat /proc/meminfo | grep -E "^(MemTotal|MemAvailable|SwapTotal|SwapFree)"'
用的时候一行命令就能看到全局。写脚本采集监控数据时,top -b -n 1和ps aux --sort输出的是纯文本,用awk和sed处理也非常方便。
5.5 组合命令时容易踩的坑
这里列几个我实际踩过的坑,希望你能绕开:
top -b -n 1输出的是整个屏幕的内容,直接grepPID可能匹配到多个行(比如进程命令行里包含相同数字),建议grep时加-w精确匹配。ps aux | grep时,grep进程本身会被列出来。用grep -v grep过滤,或者把grep写成一个方括号字符类,比如ps aux | grep "[j]ava",这样grep的命令行不会匹配自身。free -m的输出在内存很大的机器上可能超过4位数,脚本解析时注意列偏移,最好先确认列名再取列号。- 用
top -p同时监控多个进程时,多个PID用逗号分隔,不要用空格。 - 在容器里执行
free时,你看到的是宿主机还是容器本身的内存,取决于容器实现和挂载方式,判断时不要想当然。
6. 从命令到思维:如何把这些技能变成排查问题的直觉
最后我想聊一点经验性的东西。工具是学不完的,关键在遇到问题时的分析路径。我的经验是:先抓整体,再锁局部,最后追根因。
top给你整体,ps帮你锁局部,free和/proc、vmstat这类工具帮你追根因。这套思维不局限于这三个命令,netstat、ss、iostat、pidstat本质上也是同一个思路的不同维度。只要你理解了“整体—局部—根因”的路径,面对任何系统问题都不会手足无措。
很多人在面试时被问“Linux排查CPU飙升怎么弄”,回答往往是“用top看”。这个答案太粗糙。完整的回答应该是:先用top定位高CPU进程,再按H上看线程,再jstack转线程栈,结合代码定位问题。你看,整个过程里top只是第一步,后面还需要一系列工具配合。这也是我个人认为top、ps、free这三个命令最大的价值——它们是整个排查链路里的起点和锚点,而不是终点。
如果你刚开始学这些命令,不要急着背参数,先把输出看明白,再把常用参数用熟,最后慢慢形成自己的排查套路。刚开始可以刻意练习:遇到任何系统问题,不管是否紧急,都先跑一遍top、ps aux、free -h,记录当时的输出和你的判断。坚持一段时间,你会发现这些命令已经成了你肌肉记忆的一部分,看到输出就能立刻反应出系统当前是什么状态。
