Linux指令之ps使用
2021-03-12 13:30:00 阿炯

作为 Linux 系统的管理者,时常都需要查看系统的负载状况,如果系统中出现不正常的程序,用掉过多的 CPU 或内存资源,就会影响系统的效能,太严重的话甚至会造成宕机等状况。

查看系统负载(loading)与进程(process)的状况最常用的就是 ps 与 top 这两个指令,以下我们示范如何利用这两个指令自动找出系统上最耗费资源的进程,本文重点介绍ps指令。ps命令是Process Status的缩写,ps命令用来列出系统中当前运行的那些进程。ps命令可以列出当前进程的运行情况(状态、时间等信息),用于显示当前进程(process)的状态,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了多少的资源等信息。

ps介绍及Linux进程状态介绍

在Linux系统中,进程有5中状态,在其命令输出中分别用5个大写字母表示:

运行(正在运行或在运行队列中等待)
中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)
不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)
僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放)
停止(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行运行)

D 不可中断 uninterruptible sleep (usually IO)
R 运行 runnable (on run queue)
S 中断 sleeping
T 停止 traced or stopped
Z 僵死 a defunct ('zombie') process

R (TASK_RUNNING),可执行状态。
runnable (on run queue),正在运行或在运行队列中等待的进程。

S (TASK_INTERRUPTIBLE),可中断的睡眠状态。
sleeping,处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。

D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态。
uninterruptible sleep (usually IO),进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。

T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态。
traced or stopped,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行)。

Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸进程。
a defunct process,在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)。

除此之外,还有ps命令还有一些进程状态信息(状态码):
< 优先级高的进程
l 多线程状态
 前台进程
L 锁定状态
N 优先级低的进程

语法

ps [options] [--help]

选项

选项描述
-a显示所有终端机下执行的程序,除了阶段作业领导者之外。
a显示现行终端机下的所有程序,包括其他用户的程序。
-A显示所有程序。
-c显示CLS和PRI栏位。
c列出程序时,显示每个程序真正的指令名称,而不包含路径,选项或常驻服务的标示。
-C<指令名称>指定执行指令的名称,并列出该指令的程序的状况。
-d显示所有程序,但不包括阶段作业领导者的程序。
-e此选项的效果和指定"A"选项相同。
e列出程序时,显示每个程序所使用的环境变量。
-f显示UID,PPIP,C与STIME栏位。
f用ASCII字符显示树状结构,表达程序间的相互关系。
-g<群组名称>此选项的效果和指定"-G"选项相同,当亦能使用阶段作业领导者的名称来指定。
g显示现行终端机下的所有程序,包括群组领导者的程序。
-G<群组识别码>列出属于该群组的程序的状况,也可使用群组名称来指定。
h不显示标题列。
-H显示树状结构,表示程序间的相互关系。
-j或j采用工作控制的格式显示程序状况。
-l或l采用详细的格式来显示程序状况。
L列出栏位的相关信息。
-m或m显示所有的执行绪。
n以数字来表示USER和WCHAN栏位。
-N显示所有的程序,除了执行ps指令终端机下的程序之外。
-p<程序识别码>指定程序识别码,并列出该程序的状况。
p<程序识别码>此选项的效果和指定"-p"选项相同,只在列表格式方面稍有差异。
r只列出现行终端机正在执行中的程序。
-s<阶段作业>指定阶段作业的程序识别码,并列出隶属该阶段作业的程序的状况。
s采用程序信号的格式显示程序状况。
S列出程序时,包括已中断的子程序资料。
-t<终端机编号>指定终端机编号,并列出属于该终端机的程序的状况。
t<终端机编号>此选项的效果和指定"-t"选项相同,只在列表格式方面稍有差异。
-T显示现行终端机下的所有程序。
-u<用户识别码>此选项的效果和指定"-U"选项相同。
u以用户为主的格式来显示程序状况。
-U<用户识别码>列出属于该用户的程序的状况,也可使用用户名称来指定。
U<用户名称>列出属于该用户的程序的状况。
v采用虚拟内存的格式显示程序状况。
-V或V显示版本信息。
-w或w采用宽阔的格式来显示程序状况。
x显示所有程序,不以终端机来区分。
X采用旧式的Linux i386登陆格式显示程序状况。
-y配合选项"-l"使用时,不显示F(flag)栏位,并以RSS栏位取代ADDR栏位。
-<程序识别码>此选项的效果和指定"p"选项相同。
–cols<每列字符数>设置每列的最大字符数。
–columns<每列字符数>此选项的效果和指定"–cols"选项相同。
–cumulative此选项的效果和指定"S"选项相同。
–deselect此选项的效果和指定"-N"选项相同。
–forest此选项的效果和指定"f"选项相同。
–headers重复显示标题列。
–help在线帮助。
–info显示排错信息。
–lines<显示列数>设置显示画面的列数。
–no-headers此选项的效果和指定"h"选项相同,只在列表格式方面稍有差异。
–group<群组名称>此选项的效果和指定"-G"选项相同。
–Group<群组识别码>此选项的效果和指定"-G"选项相同。
–pid<程序识别码>此选项的效果和指定"-p"选项相同。
–rows<显示列数>此选项的效果和指定"–lines"选项相同。
–sid<阶段作业>此选项的效果和指定"-s"选项相同。
–tty<终端机编号>此选项的效果和指定"-t"选项相同。
–user<用户名称>此选项的效果和指定"-U"选项相同。
–User<用户识别码>此选项的效果和指定"-U"选项相同。
–version此选项的效果和指定"-V"选项相同。
–widty<每列字符数>此选项的效果和指定"-cols"选项相同。


常用参数有:
-e,-A 显示所有进程
-f 显示完整格式的输出
-l 显示长列表
-a,所有进程,加上-x参数会显示没有控制终端的进程
-u username,显示指定用户的进程,例如ps -u freeoa
-aux 按照CPU或者内存用量来筛选进程,例如ps -aux --sort -pcpu或ps -aux --sort -pmem
-C cmdlist,显示包含在cmdlist列表中的进程,例如ps -C test
-L 显示进程中的线程,例如ps -L 123,123为进程ID
-j 显示任务信息
-H 用层级显示进程,树状结构

ps -ef/aux/ax:显示所有当前进程
ps -u root:显示指定用户进程
ps -aux --sort -pcpu:根据CPU使用率来升序排序
ps -f -C getty 1:通过进程名和PID过滤,带格式显示(1是PID或者进程名)
pstree/ps -axjf:树形显示进程
ps -l :将目前属于本用户登入的 PID 与相关信息列示出来

-A 列出所有的行程
-w 显示加宽可以显示较多的信息
-au 显示较详细的资讯
-aux 显示所有包含其他使用者的进程,au(x) 输出格式 :
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND


结果列信息表示如下1:
UID:启动进程的用户
PID:进程ID
PPID:进程的父进程ID
C:进程生命周期中的CPU利用率
TTY:运行在哪个终端
TIME:进程已用CPU时间
CMD:进程的命令
F:内核分配给进程的标记
PRI:进程的优先级
NI:优先度值用来参与决定优先级
SZ:如果进程被换出,所需要的空间大小
WCHAN:进程休眠的内核函数的地址
ADDR:进程的内存地址

结果列信息表示如下2:
USER: 行程拥有者
PID: pid
%CPU: 占用的 CPU 使用率
%MEM: 占用的物理内存使用率
VSZ: 占用的虚拟内存大小
RSS: 占用的内存大小
TTY: 终端的次要装置号码 (minor device number of tty)
STAT: 该行程的状态:
    D: 无法中断的休眠状态 (通常 IO 的进程)
    R: 正在执行中
    S: 静止状态
    T: 暂停执行
    Z: 不存在但暂时无法消除
    W: 没有足够的记忆体分页可分配
    <: 高优先序的行程
    N: 低优先序的行程
    L: 有记忆体分页分配并锁在记忆体内(实时系统或捱A I/O)
START: 行程开始时间
TIME: 执行的时间
COMMAND:所执行的指令


运行ps指令可利用其列出进程的一些基本信息,按照每个进程所使用的内存排序后,列出排名最前面的几个进程,列出系统上最耗费内存的10个进程:ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head

这里的 -e 参数是代表输出所有进程的信息,而 -o 参数则是用来指定输出栏位,后面接著所有想要输出的栏位名称,这里我们让 ps 输出以下几个栏位:
pid:进程 ID(process ID)。
ppid:父进程 ID(parent process ID)。
cmd:进程的程序名称。
%mem:内存使用量(百分比)。
%cpu:CPU 使用量(百分比)。

而 --sort 参数则是指定排序的依据栏位,预设会依照数值由小到大排序,若要由大到小的方式排序的话,可以在栏位名称前加上一个负号。以这个例子来说,我们将排序的栏位指定为 -%mem,这样就可以依照内存使用量,从大到小排序。

最后将 ps 的输出以 Linux 管道(pipe)导向至 head,只保留前 10 行的资料,其余的都丢弃,以下是输出的结果。
  PID  PPID CMD                         %MEM %CPU
 7694  6668 /apps/mysql/bin/mysqld --ba 71.6  136
  617     1 /usr/lib/systemd/systemd-jo  0.2  0.0
 1200     1 /usr/sbin/rsyslogd -n        0.1  0.0
25052  1279 sshd: root@pts/1             0.0  0.0
18733  1475 pickup -l -t unix -u         0.0  0.0
25055 25052 -bash                        0.0  0.0
    1     0 /usr/lib/systemd/systemd --  0.0  0.0
25409 25055 ps -eo pid,ppid,cmd,%mem,%c  0.0  0.0
 1252  1244 /usr/sbin/zabbix_agentd: co  0.0  0.0


几个高效用法

(1)显示所有进程
ps -ax | less

(2)只显示某用户的进程
ps -u root

(3)通过cpu和内存使用来过滤进程
ps -aux | less

(4)根据 CPU、内存的使用量进行升序排序
ps -aux --sort -pcpu | less
ps -aux --sort -pmem | less

可以将它们合并到一个命令,并通过管道显示前10个结果
ps -aux --sort -pcpu,+pmem | head

(5)树形显示
ps -axjf
pstree

(6)再一些示例
To see top 5 cpu consuming process is,
ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -n 5

To see top 5 memory consuming process is,
ps -eo pid,comm,%cpu,%mem --sort=-%mem | head -n 5

ps -Ao user,uid,comm,pid,pcpu,tty --sort=-pcpu | head -n 6

ps -eo pcpu,args --sort=-%cpu | head

ps auxk-c | head -6
ps aux k-pcpu | head -6

watch "ps aux | sort -nrk 3,3 | head -n 5"

取得进程的运行时间
get the start time of a long-running linux process

ps -eo pid,lstart,cmd
ps -p PID -wo pid,lstart,cmd

ps -ewo pid,lstart,cmd
ps -axwo pid,lstart,cmd

排序后输出
ps -eo pid,etime,cmd|sort -n -k2

date; ls -ld /proc/PID /proc/$$
ls -ltrh /proc | grep PID


ps 指令输出

若要找出系统上最耗费 CPU 的程式,也是使用类似的指令,只是在排序时,将排序的栏位换成 CPU 使用量:
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head

输出为:
  PID  PPID CMD                         %MEM %CPU
 7694  6668 /apps/mysql/bin/mysqld --ba 71.6  136
    1     0 /usr/lib/systemd/systemd --  0.0  0.0
    2     0 [kthreadd]                   0.0  0.0
    4     2 [kworker/0:0H]               0.0  0.0
    6     2 [ksoftirqd/0]                0.0  0.0
    7     2 [migration/0]                0.0  0.0
    8     2 [rcu_bh]                     0.0  0.0
    9     2 [rcu_sched]                  0.0  0.0
   10     2 [lru-add-drain]              0.0  0.0


不得不说的top指令

top是一个可交互式(interactive)的工具,可以显示即时的系统负载状态,而它也可以用于输出各种系统资讯;下面的指令可将系统进程以内存的使用赖排序后,以 batch 模式输出报表,并且只保留前 10 个最耗费内存的进程:
top -b -o +%MEM | head -n 17

其中 -b 参数是 batch 模式的意思,而 -o 参数则是设定以内存用量来排序进程,最后面的 head -n 17 则是筛选 top 输出的文字内容,只保留前 17 行,剩余的内容则舍弃。输出类似这样:
top - 09:37:36 up 924 days, 19:11, 18 users,  load average: 0.31, 0.38, 0.39
Tasks: 588 total,   1 running, 584 sleeping,   3 stopped,   0 zombie
%Cpu(s):  1.5 us,  1.3 sy,  0.0 ni, 96.8 id,  0.2 wa,  0.0 hi,  0.2 si,  0.0 st
KiB Mem : 65805764 total,  3629260 free, 13488788 used, 48687716 buff/cache
KiB Swap: 31252476 total, 31252476 free,        0 used. 48208604 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 6588 mysql     20   0 14.791g 8.598g   5924 S  23.5 13.7  69125:01 mysqld
30242 root      20   0 1565460 1.298g   4568 S   0.0  2.1 123:31.58 perl
13377 root      20   0 1158688 838836 838716 S   0.0  1.3   0:15.97 sz
22640 freeoa      20   0 12.006g 836284   5400 S   0.0  1.3 316635:22 java
 2663 freeoa      20   0 21.996g 629380   4384 S   0.0  1.0   1171:12 java
 1313 root      20   0 26.973g 318356   2592 S   0.0  0.5   2657:48 java
 8269 root       1 -19 6141524  50032   1176 S   0.0  0.1   1628:44 mfsmount
28428 root      20   0  252528  43920   4584 S   0.0  0.1  20:39.61 perl
 5384 root      20   0  247060  42788   4604 S   0.0  0.1  23:14.22 perl
24473 zabbix    20   0 2547388  34232  13412 S   0.0  0.1 526:45.81 zabbix_server

若要找出最耗费 CPU 资源的进程,则改用 CPU 使用量来排序即可:
top -b -o +%CPU | head -n 17

输出会类似这样:
top - 09:38:53 up 81 days, 10:03,  1 user,  load average: 79.92, 84.23, 100.91
Tasks: 233 total,   1 running, 232 sleeping,   0 stopped,   0 zombie
%Cpu(s): 99.3 us,  0.7 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 32780076 total,   243336 free, 24093372 used,  8443368 buff/cache
KiB Swap: 16777212 total, 15778932 free,   998280 used.  7438104 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 7694 mysql     20   0   28.6g  22.4g   4544 S  1600 71.7 160315:56 mysqld
25097 root      20   0  162128   2200   1528 R   6.2  0.0   0:00.02 top
    1 root      20   0  191436   2796   1372 S   0.0  0.0  48:22.80 systemd
    2 root      20   0       0      0      0 S   0.0  0.0   0:02.26 kthreadd
    4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
    6 root      20   0       0      0      0 S   0.0  0.0   0:37.95 ksoftirqd/0
    7 root      rt   0       0      0      0 S   0.0  0.0   0:16.08 migration/0
    8 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcu_bh
    9 root      20   0       0      0      0 S   0.0  0.0  97:52.60 rcu_sched
   10 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 lru-add-drain

通常如果发现异常的进程占用了太多的CPU或内存,可选的处理方式就是把这些进程应用正常关闭,如果无法关闭的话,就可以使用 kill 或 killall 这类的指令,中止不正常程式的执行,由于上面的报表中都有每个进程的 PID,所以使用 PID 来中止特定的进程是最直接的方式。


关于linux下ps和top的cpu占用率不一致问题

ps aux是根据各类时间算出的cpu占用率,top是实时的。ps 的cpu、mem的占用率结果是如何计算出来的:

man ps 中的说明:
CPU usage is currently expressed as the percentage of time spent running during the entire lifetime of a process. This is not ideal, and it does not conform to the standards that ps otherwise conforms to. CPU usage is unlikely to add up to exactly 100%.

uptime 是系统的开发时间,通过uptime命名可以拿到该数据,pu_time 进程拿到的cpu时间片时间。ps_time 是进程实例化后的时间。

uptime  = total time system has been running.
ps_time = process start time measured in seconds from boot.
pu_time = total time process has been using the CPU.

seconds = uptime - ps_time

cpu_usage = pu_time * 1000 / seconds

print: cpu_usage / 10 "." cpu_usage % 10

示例:
uptime  = 344,545
ps_time = 322,462
pu_time =   3,383

seconds   = 344,545 - 322,462 = 22,083
cpu_usage = 3,383 * 1,000 / 22,083 = 153

print: 153 / 10 "." 153 % 10 => 15.3


man top 中的说明:
%CPU -- CPU usage
The task's share of the elapsed CPU time since the last screen update, expressed as a percentage of total CPU time. In a true SMP environment, if 'Irix mode' is Off, top will operate in 'Solaris mode' where a task's cpu usage will be divided by the total number of CPUs. You toggle 'Irix/Solaris' modes with the 'I' interactive command.

结论:top里面拿到的数据是从/proc/pid/stats拿到的,跟ps不同的是,top会默认每秒做一次数值的计算,这也是top能拿到实时监控数据的原因。


pstree命令参考

pstree命令将以树形结构显示进程和进程之间的关系,树状图将会以 pid (如果有指定) 或系统初始进程为树根(root),如果有指定使用者id(user id),则树状图会只显示该使用者所拥有的进程,它对ps而言是一个很好的补充。

使用权限:所有使用者。

它可方便用于查看进程树之间的关系,即哪个进程是父进程,哪些是子进程,清楚的看出是创建关系。以树状图显示进程间的关系(display a tree of processes)。ps命令可以显示当前正在运行的那些进程的信息,但是对于它们之间的关系却显示得不够清晰。在Linux系统中,系统调用fork可以创建子进程,通过子shell也可以创建子进程,Linux系统中进程之间的关系天生就是一棵树,树的根就是进程PID为1的init进程。

语法

pstree [-a] [-c] [-h|-Hpid] [-l] [-n] [-p] [-u] [-G|-U] [pid|user]

pstree [选项] [PID或用户名]

参数说明:
-a 显示该行程的完整指令及参数,包含启动进程的路径、参数等,如果是被内存置换出去的进程则会加上括号
-c 不使用精简法显示进程信息,即显示的进程中包含子进程和父进程,如果有重复的进程名,则分开列出(预设值是会在前面加上 *)
-h 对现在执行的程序进行特别标注
-n 根据进程PID号来排序输出,默认是以程序名排序输出的

重要的参数:
-A:各进程树之间的连接以ASCII码字符来连接
-U:各进程树之间的连接以utf8字符来连接,某些终端可能会有错误
-p:同时列出每个进程的PID
-u:同时列出每个进程的所属账号名称
-V:查看版本号

在CentOS7下可以看到所有的进程都是依附在systemd这个进程下面,它的进程PID是1,因为它是由Linux内核主动调用的一个进程。init 进程是系统启动的第一个进程,进程的 PID 是 1,也是系统中所有进程的父进程。


以树状图显示进程,相同名称的进程不合并显示,并且会显示命令行参数,如果有-p参数则同时显示每个进程的PID。
格式:pstree -a

在输出中包含命令行参数,可以使用-a命令行选项完成:
pstree -a

强制pstree在输出中展开相同的子树

默认情况下,pstree命令通过将它们放在方括号中并将它们加上重复计数前缀来合并相同的分支。

但如果愿意,可以强制该工具展开相同的树,使用-c命令行选项进行操作:
pstree -c

让pstree突出特定的过程

如果希望该工具突出显示输出中的特定进程,请使用-H命令行选项。
pstree -H [PID]

PID是想要突出显示的流程的ID。

让pstree在输出中显示进程组ID

可使用-g命令行选项:
pstree -g

这样可以看到每个进程名称后面的进程组标识在括号中显示为十进制数字。

根据PID进行pstree排序过程

默认情况下,pstree按名称排序具有相同祖先的进程。如果需要,可以使用PID进行pstree排序,也可以使用-n命令行选项进行排序:
pstree -n

注意,这种排序也称为数字排序。


使pstree显示特定于用户的进程树

如果希望pstree显示以特定用户拥有的进程为根的所有进程树,那么只需将该用户的名称作为输入传递给该命令:
pstree freeoa


限制pstree到一个特定的过程

如果希望pstree仅显示特定进程的父级和子级信息,请使用-s选项。
pstree -s [PID]

例如想限制pstree输出到我系统上的firefox进程,所以执行了下面的命令:
pstree -s 1234

特别表明在运行的进程
pstree -apnh //显示进程间的关系

同时显示用户名称
pstree -u //显示用户名称