搞Linux运维或者开发的人,早晚都得直面这三个命令:top、ps、free。不管你是刚入行的小白,还是已经写过不少脚本的老手,只要机器出问题,第一反应基本都是“上去看看进程和内存”。这三个命令就是Linux下排查问题最基础、最常用的三件套。top负责实时盯梢进程的一举一动,ps负责在某个瞬间给进程拍一张高清快照,free则专门查看内存的整体使用情况。它们解决的问题不一样,但组合起来基本能覆盖日常大部分排查场景。这篇文章我会从实际使用的角度,把这三个命令的用法、输出解读、常见坑一次性讲明白,适合刚接触Linux的初学者,也适合想系统梳理一遍命令细节的开发者。
1. 三个命令的分工逻辑与选型思路
1.1 为什么偏偏是这三个命令
很多人刚学Linux时容易犯一个毛病:背了一堆命令,真到用的时候不知道选哪个。其实top、ps、free这三个正好形成了一套完整的“进程和资源体检”组合。你可以把它们理解成医院里的三个检查项目:top是动态心电图,持续记录心脏每一秒的跳动情况;ps是CT扫描,在某个时间点把整个身体的结构看得清清楚楚;free是血常规,专门看血液里各种成分的含量是否正常。
top最大的特点是“动态”,它默认每隔几秒刷新一次界面,实时显示当前系统里CPU占用最高的进程、内存占用情况、系统负载等。当你需要观察某个进程是不是一直在吃CPU、系统负载是不是持续飙升时,top是最直观的。
ps的特点是“静态”,它只看执行那一刻的系统进程状态,输出完就结束。它的优势在于可以自由定制输出字段,配合管道符做过滤、排序、提取,非常适合写脚本做定时巡检。
free的功能非常聚焦,就是看内存总容量、已使用、可用量,以及最重要的buffer/cache情况。内存类的排查问题,几乎都要从free入手。
1.2 命令组合使用的经典场景
在实际排查中,这三个命令很少单独使用。我给你列举几个最常见的组合套路。
场景一:服务器响应变慢,怀疑是某个进程把CPU打满了。先跑top按CPU排序,看到PID后,再跑ps -p PID -o pid,ppid,user,stat,command确认这个进程的启动命令和父进程,最后用free -h确认内存是否也吃紧。整个过程不超过一分钟。
场景二:内存报警,但不知道谁占的。先跑free -m确认内存确实不足,再用ps aux --sort=-rss按物理内存占用排序,找出吃内存大户,随后进一步定位。
场景三:写监控脚本,需要定时采集系统状态。top -b -n 1在批处理模式下输出一次快照,ps -eo pid,comm,%cpu,%mem --sort=-%cpu提取指定列,free -m记录内存值,三个命令的输出组合起来就是一份完整的巡检数据。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. top命令:实时监控进程的现场直播
2.1 top界面拆解:上半部分是系统概要,下半部分是进程列表
你在终端敲top回车,会看到一个全屏的刷新界面。很多人第一眼看过去觉得内容密,其实它分成了两个清晰的区块。
顶部区域是系统概要信息,一般有5行左右。第一行显示当前时间和机器已经运行了多久,以及有几个用户在线,最后是系统负载平均值(load average),分别代表过去1分钟、5分钟、15分钟的平均负载。这里要注意,负载值不是越低越好,也不是超过1就代表有问题,它需要结合CPU核心数来看。比如4核机器,负载超过4才意味着任务队列积压。
第二行和第三行是进程统计和CPU状态。进程统计能看到总进程数,以及正在运行、休眠、停止、僵尸状态的进程数量。CPU状态这一行经常有人看懵,us代表用户态占用,sy代表内核态占用,ni代表被调整过优先级的进程占用,id是空闲比例,wa是等待I/O完成的比例,hi和si分别是硬件中断和软件中断。排查CPU问题时,重点看us和sy。us高说明是用户程序在消耗CPU,sy一直很高就要怀疑是不是内核层面出了问题,wa高则意味着磁盘或网络I/O是瓶颈。
第四行和第五行是内存和交换分区使用情况。这里的信息和free命令输出是对应的,total是总内存,free是完全没有被使用的内存,used是已经被用的内存,buff/cache是缓存和缓冲区占用。注意,used并不等于真实使用的内存,因为buff/cache在内存紧张时是可以被回收的。后面讲free的时候会详细展开。
下半部分就是进程列表了,默认按CPU占用率降序排列。每一行代表一个进程,包含PID、用户、CPU占用、内存占用、状态、启动命令等字段。top默认显示的CPU占用是相对单个核心的百分比,所以多核机器上你看到某个进程CPU超过100%是正常的。
2.2 top的交互式快捷键:不用记太多,这几个最实用
top进入全屏界面后,你可以直接按键盘上的字母触发功能。我平时用得最多的有以下几个:
P:按CPU占用率从高到低排序,排查CPU问题时进场第一步。M:按内存占用率从高到低排序,查内存大户很好用。k:杀掉指定PID的进程,按下后会提示输入PID,再杀。比另开终端敲kill快。1:展开或折叠每个CPU核心的使用情况,多核机器上看出哪个核被单独打满了。H:切换线程模式,默认显示进程,按H之后显示的是每个线程。排查多线程程序某个线程CPU飙高时,这个开关是必须的。c:切换是否显示完整命令行,默认只显示进程名,按c后会显示完整的启动命令和参数,定位问题进程时很有用。E和e:分别切换顶部内存和进程内存的显示单位,在B、KB、MB、GB之间循环。大内存机器上建议切到GB,数字看起来更直观。q:退出top。
如果你写脚本需要在批处理模式下用top,记住这两个参数:-b表示批处理模式,-n 1表示只执行一次,不做实时刷新。比如top -b -n 1就能得到一帧完整的top输出,适合采集快照。-d可以指定刷新间隔秒数,比如top -d 2就是每2秒刷新一次。
2.3 top输出里的几个易误解的细节
先讲CPU占用。top里进程的CPU列,代表的是该进程从上次刷新到这次刷新之间消耗的CPU时间比例。默认情况下它是相对单核的,所以8核机器上100%意味着占满了一个核心,800%才是占满全部核心。很多新手看到自己被监控的进程CPU显示300%就慌了,其实只要没超过核心数乘以100,都还算“单进程吃满多核”的范畴。
再讲load average。有次我的同事看到load average是17,马上申请扩容,结果我一看机器是32核的,这个负载根本不算高。负载值可以粗略理解为“处于可运行状态和不可中断睡眠状态的进程平均数”,它反映的是系统整体的繁忙程度。判断负载是否过高,最直接的办法是和CPU核心数比较。负载长期超过核心数,说明任务排队的现象比较明显,系统确实忙不过来了。
还有一个容易被忽略的字段是进程状态列,top里用R、S、D、Z等字母表示。R代表正在运行或可运行,S是休眠状态,D是不可中断的睡眠,通常是在等待I/O,Z是僵尸进程。如果你看到很多Z,说明有进程没有被父进程正确回收,这是需要重视的信号。
3. ps命令:进程静态快照的精确工具
3.1 ps的两种风格和常用组合
ps是process status的缩写,它的历史十分悠久,也因此造成了两种命令风格:Unix风格用单横线,比如ps -ef;BSD风格不用横线,比如ps aux。新手经常疑惑这两个命令到底有什么区别,其实输出内容大同小异,主要是字段名和展示形式略有差异。
ps -ef以标准的Unix格式输出全部进程,第一列UID、第二列PID、第三列PPID(父进程PID)、第四列C(CPU利用率)、后面是启动时间和执行的命令。ps aux以BSD格式输出,多了USER、%CPU、%MEM、VSZ、RSS、STAT等字段,信息量更丰富一些。
我的个人习惯是:临时看进程用ps aux,因为字段直观,能直接看到CPU和内存占用百分比;写脚本提取信息用ps -eo,因为可以精确控制输出的字段和顺序。
ps -eo中的e表示全部进程,o表示自定义输出字段,比如ps -eo pid,ppid,user,stat,%cpu,%mem,cmd --sort=-%cpu,这条命令把所有进程按CPU占用从高到低排列,只显示指定列。--sort参数支持加负号表示降序,不加则升序,比如--sort=rss就是按内存从小到大排。这种写法在Shell脚本里非常实用,输出的每一列都在你的掌控之中。
3.2 常见进程状态的完整解读
ps的STAT字段包含的信息量很大,但很多教程只讲R、S、D、Z几个字母,其实它的格式是多个字符组成的。第一位是主状态,R运行、S休眠、D不可中断睡眠、Z僵尸、T停止。后面的附加字符有特殊含义,例如:
<:高优先级进程。N:低优先级进程(nice值为正)。L:进程有页面锁定在内存中。s:这个进程是会话的领头进程,简单理解就是一个进程组的领导者。l:多线程进程。+:位于前台进程组。
我举两个实际例子。比如你看到某个进程的状态是Ssl,翻译过来就是:休眠状态、会话领导者、多线程。看到Z就要注意了,说明这个进程已经终止但其父进程没有调用wait系列函数回收它,残留在进程表里。少量僵尸进程通常不影响系统运行,但如果数量持续增长,很可能是程序有bug或者父进程僵死,需要找到父进程处理或者重启相关服务。
3.3 快速定位问题进程的ps技巧
用ps排查问题时,我常用的思路是先按资源占用排序,再过滤关键词。
比如要找出哪个进程占用内存最大,可以用ps aux --sort=-%mem | head -n 10,这就拿到了内存占用最高的前10个进程。要定位和某个程序相关的所有进程,可以用ps -ef | grep nginx,但这样会把grep自己这一行也带出来。解决这个经典问题的办法是用ps -ef | grep [n]ginx,用方括号把第一个字母括起来,grep就不会匹配到自身了,因为命令行里显示的是grep [n]ginx,grep的目标串是[n]ginx,这个串在进程列表里只匹配真正的nginx进程。这是一个在运维圈流传很广的小技巧,原理是利用了grep进程自身命令行和匹配模式的区别。
如果已经知道PID,想看这个进程的详细信息,可以直接ps -p PID -o pid,ppid,user,stat,comm,args。其中comm是进程名,args是完整的命令行参数,两者区别在于comm只显示可执行文件名,args会显示所有启动参数。遇到多个同名进程但启动参数不同时,args是最可靠的区分依据。
3.4 进程父子关系与PPID的实际价值
ps -ef输出中的PPID字段是经常被忽略但实际价值很高的信息。比如你发现服务器上多了一个可疑的进程,第一时间应该看它的PPID是谁。如果PPID是1,说明这个进程已经被init/systemd直接收养,通常意味着它的父进程先退出了,这个进程变成了孤儿进程。如果PPID是某个正常业务的PID,那说明这个可疑进程是该业务启动的子进程,排查方向就完全不同。
还有一个经典场景是排查端口占用。lsof -i:8080能找到监听8080端口的进程,但有时候装了lsof不方便,可以用另一种方式:netstat -tlnp | grep 8080,拿到PID后,再用ps -fp PID看这个进程的完整信息,包括它的父进程是谁,从而判断这个端口到底是被谁拉起的。
4. free命令:内存视角的全局体检
4.1 free的常用参数和输出解读
free命令的用法非常简洁,常用参数也就那么几个。free -m以MB为单位显示,free -g以GB为单位显示,free -h自动选择人类易读的单位,这个在交互式排查时最常用。-s参数可以持续刷新,比如free -s 3就是每3秒输出一次,搭配-c指定次数可以控制循环次数,比如free -s 3 -c 5循环5次后自动退出。
free输出的核心列是total、used、free、shared、buff/cache、available。这里一定要搞清楚每列的含义,尤其是used和free,很多人直接理解成“used就是已经用掉的内存,free就是还能用的内存”,这个理解在现在Linux内核的内存管理下是片面的。
buff/cache尤其要留意。Linux会尽量把空闲内存用作页缓存(page cache),来加速磁盘文件的读写。你读过的文件、执行过的程序,其数据都可能留在cache里。这会导致free命令显示的内存使用率偏高,free列很小。但实际上,当应用程序需要内存时,内核会回收一部分buff/cache空间来满足分配需求,所以buff/cache并不是“占着茅坑不拉屎”。
available这一列才是真正能反映“还有多少内存可用”的指标。它是内核根据当前内存压力和可回收性估算出的数值。判断内存是否出现瓶颈,最靠谱的方式是比较used和available,而不是盯着free那一列。
4.2 计算真实内存使用率的方法
内存使用率的计算方法有很多版本,但比较推荐的是基于available的计算方式:
code复制内存使用率 = (total - available) / total * 100%
为什么不建议用used/total?因为used包含了buff/cache,而buff/cache是可以被回收再分配的。我曾经在一台内存16G的机器上看到free显示used 15.2G,free只有不到400M,但如果按available来算,实际可用内存还有7G多,因为那15.2G里有接近7G是页缓存。如果按used/total去算,你会得到95%的荒谬结论,然后白忙活一场,加上swap配置再一看,好家伙,swap一点都没用,说明系统还没到内存紧张的程度。
在free命令输出里,Swap行也需要注意。如果Swap的used从0开始不断增长,说明物理内存真的不够用了,数据被换到磁盘上,这往往会导致性能断崖式下跌。遇到swap持续增长时,排查重点不是swap本身,而是谁在申请内存。
4.3 free、top、ps三者内存数据的联系和差异
同一个时刻,用top看内存、free看内存、ps看单个进程的内存,三者的数值口径是有差异的。top顶部的内存行数据来自/proc/meminfo,和free的输出基本一致,只是展示方式略有不同。而ps输出中每个进程的RSS(Resident Set Size)表示该进程实际驻留在物理内存中的页面大小,但它包含了共享库被多个进程共同占用的部分。这就导致了一个现象:把所有进程的RSS加起来,会大于free显示的已使用内存总量,因为共享库的页面被重复计算了。
所以你在排查单个进程内存占用时,应该看RSS;在衡量全系统内存水位时,应该以free的available为准;在动态观察内存变化时,用top顶部或者free -s刷新都行。三者的职责不同,不存在孰优孰劣。
4.4 如何快速判断内存是否泄漏
内测环境里经常遇到的一种情况是:服务跑几天,内存占用缓慢上升,怀疑泄漏。排查步骤通常是这样:
先用ps aux --sort=-rss | head -n 5找出物理内存占用增长的进程,记下RSS数值。然后用free -m记录系统整体内存水位。隔一段时间重复一次,看这个进程的RSS是不是只增不减。注意,Java等带有JVM的进程和大量使用glibc malloc的程序,内存增长可能是正常的,因为分配器不一定即时把释放的内存还给操作系统。此时要区分“还在正常范围的内存缓存”和“真的泄漏”不是一件简单的事,通常还要结合top的RES列长时间观察,或者到/proc/PID/smaps里看具体的虚拟内存区。
一个我自己用过的快速判断技巧是:如果进程的CPU比较空闲,但RSS依然持续上涨,比如每小时涨几百MB,而且释放操作之后不回落,那么这个进程大概率存在真正意义上的内存泄漏。可以用ps -o pid,rss,vsz,etime,cmd -p PID把这个进程的运行时间和RSS对应起来,方便判断增长速率。
5. 实战:用这三件套排查一次服务器卡顿
5.1 案例背景与排查思路
我印象里有一次线上告警说是某台应用服务器响应变慢。登录机器后,我严格按照“先看整体,再抓进程,最后确认内存”的顺序排查。
第一步,跑top -b -n 1 | head -n 15,先看系统概要和占用最高的几个进程。输出里load average是9.61、8.75、8.02,机器是4核的,这已经明显超载了。CPU那行里us和wa都很高,wa有30%多,说明磁盘I/O可能已经开始拖慢CPU了。
第二步,看到top列表里有个java进程CPU飙到380%,显然它是吃CPU的元凶。接着用ps -p PID -o pid,ppid,user,%cpu,%mem,etime,cmd确认它的启动时间、运行用户和完整命令行,发现是刚发版不到半小时的新版本服务。
第三步,跑free -h看内存。total 16G,used 13G,buff/cache 2G,available只剩不到1G。内存也确实紧张。再结合top里wa高的情况,基本可以推断:新版本服务内存占用过大,系统开始使用swap,而swap操作的I/O压力反过来导致wa升高,进一步拖慢整体性能。
5.2 定位并验证问题进程
在这个案例里,ps的--sort参数帮了大忙。我跑了:
bash复制ps aux --sort=-%cpu | head -n 5
ps aux --sort=-rss | head -n 5
两条命令一对比,发现CPU占用最高和RSS最高的都是那同一个java进程,进一步确认了它就是问题根源。随后我又用ps -fp PID看到它的父进程是systemd,也就是由systemd直接启动的,说明这不是别人临时拉起的进程,而是服务本身。所以问题定位回到了业务层面,直接联系研发确认新版本是不是存在内存配置不当或者代码层面的内存增长。
另外排查时还注意到了一个细节:top列表里有几个进程状态是D,也就是不可中断睡眠,基本都是在等待磁盘I/O完成。这个现象解释了wa为什么高。D状态进程多的时候,即使你尝试杀掉它们,也不是立刻生效,因为这些进程可能正处于等待I/O的内核路径中。
5.3 排查过程的经验小结
整个排查过程用到的核心命令就三个,但信息和推断的链路非常清晰:top给宏观现象,ps找出具体嫌疑进程,free确认内存水位。无论什么卡顿问题,都可以按这个思路来。
有几个心得值得单独提一下。第一,先看整体再下结论,不要上来就按内存排序找进程,容易带偏方向。第二,CPU、内存、I/O往往是联动的,top里wa高的时候,内存再吃紧,大概率就是swap在拖后腿。第三,拿到PID后一定记得看PPID和启动时间,这两个信息能帮你快速区分“手工启动的临时进程”和“服务管理器托管的正式进程”。
6. 常见问题与排查技巧实录
6.1 top里的CPU占用超过100%,是不是系统出问题了
不是。top显示的进程CPU占用是相对单个核心的百分比。多核处理器上,一个多线程进程可以同时使用多个核心,显示200%、400%都是正常的。判断依据是看占用比例是否超过核数乘以100%。比如8核机器上,某个进程CPU到800%,说明它把8个核心全部打满了,这才是需要关注的信号。使用top后按1展开各核心使用率,可以更直观地看到是单核打满还是多核分摊。
6.2 ps aux和ps -ef到底选哪个
两个命令的底层读取逻辑相似,输出字段不同。ps aux带%CPU、%MEM、RSS、STAT等字段,适合交互式排查;ps -ef包含PPID,适合查看进程父子关系。如果你需要自定义精确的列,直接ps -eo。我在日常中更推荐你掌握ps aux和ps -eo两个用法,前者看现场,后者写脚本。
6.3 free显示内存用了95%,机器是不是快挂了
先别急。回到第4节讲的核心:看available,不要看free。如果available还很充足,说明缓存占了很大比例,内存并没有真正吃紧。真正需要紧张的条件是:available持续走低,同时swap的used在增长。这时候再排查谁在占用内存才有意义。网上很多“内存告警”误报,都是因为监控脚本只取used/total,没有考虑到buffer/cache的可回收特性。
6.4 僵尸进程怎么处理
僵尸进程本身不占用CPU和内存,它只是残留在进程表里的一个条目。但如果父进程不回收,僵尸进程会一直累积。直接kill僵尸进程的PID是无效的,它已经死了,你要处理的是它的父进程。用ps -o ppid= -p 僵尸PID查出父进程PID,然后决定是通知父进程正确回收、重启父进程,还是让init/systemd接管。如果父进程是业务进程,建议直接重启这个业务,通常僵尸进程就会被清理掉。
6.5 top命令在脚本里为什么会输出乱码或格式错乱
在非交互环境下,比如通过cron定时任务执行top命令,top会检测到不是终端,自动进入批处理模式,但如果你的脚本里写top -n 1是没有问题的。真正容易出问题的是一些发行版对top输出做了颜色高亮,在重定向到文件时会出现转义字符。解决方法是加-b显式指定批处理模式,同时建议使用top -b -n 1 -w 512,-w参数可以调整输出行的宽度,避免长命令行被截断。
6.6 用这三个命令写一个简单的巡检脚本
最后分享一个我经常用的小脚本框架,三合一的采集方式:
bash复制#!/bin/bash
# 采集时间
echo "===== Time: $(date '+%Y-%m-%d %H:%M:%S') ====="
# 系统负载与占用最高的5个进程
top -b -n 1 | head -n 12
echo "--- top CPU process ---"
ps -eo pid,ppid,user,stat,%cpu,%mem,cmd --sort=-%cpu | head -n 6
echo "--- top MEM process ---"
ps -eo pid,ppid,user,stat,%cpu,%mem,cmd --sort=-%mem | head -n 6
echo "--- Memory Status ---"
free -h
这套脚本收集的信息,足够支撑日常巡检中90%的问题初判。有了初步结论再人工深入,效率会高很多。个人经验是:与其花大价钱上监控平台,不如先把这三个命令用得滚瓜烂熟,大部分问题在登进机器的前五分钟就已经能定位得八九不离十了。
