Linux查看系统进程与资源使用情况
2012-11-03 18:52:03 阿炯

本站赞助商链接,请多关照。 Linux性能监控工具汇总:
iostat 磁盘性能监控
vmstat 虚拟内存性能监控、CPU监控(进程上下文切换、CPU利用率)
top 系统负载、CPU使用率、各个进程的详细报告(CPU使用率、内存使用情况)等
free 内存使用情况
ps 命令严格上不算是性能监控工具,可以配合上述命令,找到占有系统资源较高的进程


下面简单地介绍了Linux系统中常见的资源使用的指令,涉及负载、内存、磁盘i/o、综合使用等方面的情况。

1、top:
主要参数
d:指定更新的间隔,以秒计算。
q:没有任何延迟的更新。如果使用者有超级用户,则top命令将会以最高的优先序执行。
c:显示进程完整的路径与名称。
S:累积模式,会将己完成或消失的子行程的CPU时间累积起来。
s:安全模式。
i:不显示任何闲置(Idle)或无用(Zombie)的行程。
n:显示更新的次数,完成后将会退出to

显示参数:
PID(Process ID):进程标示号。
USER:进程所有者的用户名。
PR:进程的优先级别。
NI:进程的优先级别数值。
VIRT:进程占用的虚拟内存值。
RES:进程占用的物理内存值。
SHR:进程使用的共享内存值。
S:进程的状态,其中S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值是负数。
%CPU:该进程占用的CPU使用率。
%MEM:该进程占用的物理内存和总内存的百分比。
TIME+:该进程启动后占用的总的CPU时间。
Command:进程启动的启动命令名称,如果这一行显示不下,进程会有一个完整的命令行。
top命令使用过程中,还可以使用一些交互的命令来完成其它参数的功能。这些命令是通过快捷键启动的。
<空格>:立刻刷新。
P:根据CPU使用大小进行排序。
T:根据时间、累计时间排序。
q:退出top命令。
m:切换显示内存信息。
t:切换显示进程和CPU状态信息。
c:切换显示命令名称和完整命令行。
M:根据使用内存大小进行排序。
W:将当前设置写入~/.toprc文件中。这是写top配置文件的推荐方法。

2、free
free命令用来显示内存的使用情况,使用权限是所有用户。

格式
free [-b-k-m] [-o] [-s delay] [-t] [-V]

主要参数
-b -k -m:分别以字节(KB、MB)为单位显示内存使用情况。
-s delay:显示每隔多少秒数来显示一次内存使用情况。
-t:显示内存总和列。
-o:不显示缓冲区调节列。

3、uptime
20:11:15 up 45 min,  3 users,  load average: 1.23, 1.32, 1.01
系统开机运转到现在经过的时间
连线的使用者数量
最近一分钟,五分钟和十五分钟的系统负载
参数: -V 显示版本资讯。

4、vmstat
这个指令反应的是系统综合运行情况的指令,包含了较多信息。
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 0  0  35396  14688  30696 142328    0    0     1     3    3    4  0  0 100  0

1)观察磁盘活动情况
磁盘活动情况主要从以下几个指标了解:
bi:表示从磁盘每秒读取的块数(blocks/s)。数字越大,表示读磁盘的活动越多。
bo:表示每秒写到磁盘的块数(blocks/s)。数字越大,表示写磁盘的活动越多。
wa:cpu等待磁盘I/O(未决的磁盘IO)的时间比例。数字越大,表示文件系统活动阻碍cpu的情况越严重,因为cpu在等待慢速的磁盘系统提供数据。wa为0是最理想的。如果wa经常大于10,可能文件系统就需要进行性能调整了。

2)观察cpu活动情况
vmstat比top更能反映出cpu的使用情况:
us:用户程序使用cpu的时间比例。这个数字越大,表示用户进程越繁忙。
sy:系统调用使用cpu的时间比例。注意,NFS由于是在内核里面运行的,所以NFS活动所占用的cpu时间反映在sy里面。这个数字经常很大 的话,就需要注意是否某个内核进程,比如NFS任务比较繁重。如果us和sy同时都比较大的话,就需要考虑将某些用户程序分离到另外的服务器上面,以免互 相影响。
id:cpu空闲的时间比例。
wa:cpu等待未决的磁盘IO的时间比例。

5、iostat
用于统计CPU的使用情况及tty设备、硬盘的I/O量
参数:
-c:只显示CPU行
-d:显示磁盘行
-k:以千字节为单位显示磁盘输出
-t:在输出中包括时间戳
-x:在输出中包括扩展的磁盘指标

avg-cpu:  %user   %nice    %sys %iowait   %idle
20.25    0.18    2.61   76.39    0.57
%iowait 等待本地I/O时CPU空闲时间的百分比
%idle 未等待本地I/O时CPU空闲时间的百分比

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
hda               9.86       284.34        84.48     685407     2036
每秒传输数(tps)、每秒512字节块读取数(Blk_read/s)、每秒512字节块写入数(Blk_wrtn/s)和512字节块读取(Blk_read)和写入(Blk_wrtn)的总数量。


关于CPU利用率。根据经验来看,用户空间进程占用CPU比例在 65-70%之间,内核(系统)CPU比例在30%-35%之间。一般不能超过这个比例,超过这个比例,系统性能就会降低,平均负载升高。

进程上下文切换。上下文切换和CPU利用率应该联系起来,如果CPU利用率低,那么上下文切换稍高点也能接受。上下文切换也是需要消耗CPU资源的,频繁的切换必将使得CPU利用率升高。系统占用CPU的利用率这么高?可认为是程序运行时的进程上下文频繁切换所导致的,这是因为进程/线程的调度室通过内核子系统进程调度程序来调度的,频繁的切换说明进程调度程序也是十分密集地占用CPU,因此导致系统占用CPU的时间很高;此外,系统调用也是耗费了一部分时间片的,因此系统占用CPU的比例很高的话,而用户空间进程占有CPU的比例相对就低了很多。

运行队列中等待运行的进程数。每个CPU核心中等待处理的进程数不应该超过3个线、进程。如4核心的机器,那么队列的最大值应该不超过12个。

平均负载。平均负载值是平均每核心CPU的负载应该控制在0.7,最好不要超过1,超过4性能就会非常低了。

使用top命令和vmstat命令搭配使用:top命令可以看到整体情况,也可以看到每个任务消耗资源的情况。使用vmstat命令查看队列中的任务书、进程上下文切换。


Linux CPU Utilization

Finding CPU utilization is one of the important tasks. Linux comes with various utilities to report CPU utilization. With these commands, you will be able to find out:
Display the utilization of each CPU individually (SMP cpu)
Find out your system's average CPU utilization since the last system reboot
Determine which process is eating the CPU(s)


The top command monitors CPU utilization, process statistics, and memory utilization. The top section contains information related to overall system status – uptime, load average, process counts, CPU status, and utilization statistics for both memory and swap space.

Top command to find out Linux cpu usage

You can see Linux CPU utilization under CPU statistics. 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 (multiple CPUS), top will operate in number of CPUs. Please note that you need to type q key to exit the top command display. The top command produces a frequently updated list of processes. By default, the processes are ordered by percentage of CPU usage, with only the "top" CPU consumers shown. The top command shows how much processing power and memory are being used, as well as other information about the running processes.

htop is similar to top command but allows you to scroll vertically and horizontally and much more.

Find Linux CPU utilization using mpstat and other tools

Please note that you need to install a special package called sysstat to take advantage of following commands.

Display the utilization of each CPU individually using mpstat

If you are using SMP (Multiple CPU) system, use mpstat command to display the utilization of each CPU individually. It report processors related statistics.The mpstat command display activities for each available processor, processor 0 being the first one. Global average activities among all processors are also reported. The mpstat command can be used both on SMP and UP machines, but in the latter, only global average activities will be printed:
# mpstat -P ALL

Report CPU utilization using the sar command

Comparison of CPU utilization

The sar command writes to standard output the contents of selected cumulative activity counters in the operating system. The accounting system, based on the values in the count and interval parameters. For example display comparison of CPU utilization; 2 seconds apart; 5 times, use:
# sar -u 2 5
Output (for each 2 seconds. 5 lines are displayed)

Where,
-u 12 5 : Report CPU utilization. The following values are displayed:
%user: Percentage of CPU utilization that occurred while executing at the user level (application).
%nice: Percentage of CPU utilization that occurred while executing at the user level with nice priority.
%system: Percentage of CPU utilization that occurred while executing at the system level (kernel).
%iowait: Percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.
%idle: Percentage of time that the CPU or CPUs were idle and the system did not have an outstanding disk I/O request.

To get multiple samples and multiple reports set an output file for the sar command. Run the sar command as a background process using.
# sar -o output.file 12 8 >/dev/null 2>&1 &

Better use nohup command so that you can logout and check back report later on:
# nohup sar -o output.file 12 8 >/dev/null 2>&1 &

All data is captured in binary form and saved to a file (data.file). The data can then be selectively displayed ith the sar command using the -f option.
# sar -f data.file

Find out who is monopolizing or eating the CPUs

Finally, you need to determine which process is monopolizing or eating the CPUs. Following command will displays the top 10 CPU users on the Linux system.
# ps -eo pcpu,pid,user,args | sort -k 1 -r | head -10
OR
# ps -eo pcpu,pid,user,args | sort -r -k1 | less

iostat

You can also use iostat command which report Central Processing Unit (CPU) statistics and input/output statistics for devices and partitions. It can be use to find out your system’s average CPU utilization since the last reboot.which gives you three outputs every 5 seconds (as previous command gives information since the last reboot):
$ iostat -xtc 5 3

vmstat

The vmstat command shows information about processes, memory, paging, block IO, traps, disks and cpu activity. Run vmstat as follows:
vmstat
vmstat [options]
vmstat [interval] [count]


Linux 进程的那些事

看完了上面的性能测量工具的使用,是不是还是对这些工具背后的工作原理感到困惑,没关系,那是因为没有了解一些系统进程方面的知识。

1.1 什么是进程

进程是 UNIX/Linux 用来表示正在运行的程序的一种抽象概念,所有系统上面运行的的数据都会以进程的形态存在。

1.2 进程的组成部分
一个进程由一个地址空间和内核内部的一组数据公同组成,地址空间是由内核标记出来供进程使用的一组内存页面(页面是管理内存的单位,页面大小通常是 1KB 或 8KB)。它包含进程正在执行的代码、库、进程变量、进程栈以及进程正在运行时内核所需要的各种其他信息。

内核的内部数据结构记录了有关每个进程的各种信息,其中非常重要的一些信息有:
进程的属主;
进程的信号掩码(一个记录,确定要封锁哪些信号);
进程已打开的文件和网络端口的信息;
进程执行的优先级;
进程的当前状态(睡眠状态、停止状态、可运行状态等等);
进程的地址空间映射。

1.3 子进程与父进程
每个进程都有一个唯一的 PID(Process ID),进程必须克隆自身去创建一个新进程。克隆出的进程能够把它正在运行的那个程序替换成另一个不同的程序。当一个进程被克隆时,原来的进程就叫做父进程 PPID(Parent Process ID),而克隆出的副本则叫做子进程。进程的 PPID 属性就是克隆它的父进程的 PID。以一个实例加深对子进程与父进程的理解:在目前的 bash 环境下,再出发一次 bash ,并以 ps -l 命令观察进程 PID、PPID 的输出信息。
# ps -l     //第一个 bash 的 PID 是 1363
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0  1363  1322  0  80   0 - 28864 do_wai pts/1    00:00:00 bash
0 R     0  1484  1363  0  80   0 - 38314 -      pts/1    00:00:00 ps

# bash    //执行 bash 进入到子程序的环境中      
# ps -l  //第二个 bash 的 PID 是 1487 , 它的 PPID 就是第一个 bash 的 PID 1363 
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0  1363  1322  0  80   0 - 28864 do_wai pts/1    00:00:00 bash
4 S     0  1487  1363  0  80   0 - 28864 do_wai pts/1    00:00:00 bash
0 R     0  1500  1487  0  80   0 - 38314 -      pts/1    00:00:00 ps

1.4 特殊进程
Linux 有三个特殊进程,idle 进程(PID=0),init 进程(PID=1),kthreadd(PID=2)。

idle 进程

idle 进程由系统自动创建的第一个进程, 运行在内核态,也是唯一一个没有通过 fork 或者 kernel_thread 产生的进程。完成加载系统后,演变为进程调度、交换。

init 进程

Linux 的所有进程都是有 init 进程创建并运行的。首先 Linux 内核启动,然后在用户空间中启动 init 进程,再启动其他系统进程。在系统启动完成完成后,init 将变为守护进程监视系统其他进程。

在CentOS 7系统里面,可以 ls 看到 init 进程是被软连接到 systemd 的。
# ls -al /usr/sbin/init
lrwxrwxrwx 1 root root 22 Apr 26 11:07 /usr/sbin/init -> ../lib/systemd/system

系统启动之后,init 进程会启动很多 daemon 进程,为启动运行提供服务,比如 httpd、ssh 等等,然后就是 agetty,让用户登录,登录后运行 shell(bash),用户启动的进程都是通过shell 运行的。执行 ps -ef 命令会发现 PID 1 的进程就是我们的 init 进程 systemd ,PID 2 的进程是内核现场 kthreadd ,这两个在内核启动的时候都见过,其中用户态的不带中括号,内核态的带中括号。

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0  2019 ?        00:12:54 /usr/lib/systemd/systemd --system --deserialize 24
root         2     0  0  2019 ?        00:00:01 [kthreadd]
root         3     2  0  2019 ?        00:03:10 [ksoftirqd/0]
root         5     2  0  2019 ?        00:00:00 [kworker/0:0H]
root         7     2  0  2019 ?        00:00:00 [migration/0]
...
root     23086 23085  0 10:23 pts/3    00:00:00 su - root
root     23087 23086  0 10:23 pts/3    00:00:00 -bash
root     24529     2  0 16:28 ?        00:00:00 [kworker/0:2]
root     25448     2  0 16:33 ?        00:00:00 [kworker/0:0]
root     25861     2  0 16:36 ?        00:00:00 [kworker/u2:0]
...
root     30648     1  0  2019 ?        00:00:00 /usr/lib/systemd/systemd-udevd
root     30936     1  0  2019 ?        00:01:06 /usr/sbin/crond -n
chrony   32061     1  0  2019 ?        00:00:07 /usr/sbin/chronyd

sshd 的父进程是 1,pts 的父进程是 sshd,bash 的父进程是 pts,ps -ef 这个命令的父进程是 bash,这样这个子父进程的关系就比较清晰了。

# ps -ef|grep sshd
root      1299     1  0 12:06 ?        00:00:04 /usr/sbin/sshd -D
root      6008  1299  0 16:49 ?        00:00:00 sshd: root@pts/0
root      6415  1299  2 17:07 ?        00:00:00 sshd: root [priv]
sshd      6416  6415  0 17:07 ?        00:00:00 sshd: root [net]
root      6420  6012  0 17:07 pts/0    00:00:00 grep --color=auto sshd

# ps -ef|grep bash
root      6012  6008  0 16:49 pts/0    00:00:00 -bash
root      6457  6012  0 17:10 pts/0    00:00:00 grep --color=auto bash



kthreadd 进程

kthreadd 进程由 idle 通过 kernel_thread 创建,并始终运行在内核空间,负责所有内核线程的调度和管理,所有的内核线程都是直接或者间接的以 kthreadd 为父进程。

1.5 进程的优先级
Linux 是多人多任务的环境,由 top 的输出结果也发现系统同时间有非常多的程序在运行中,叧是大部分的程序都在休眠 (sleeping) 状态而已。如果所有的程序同时被唤醒,那 CPU 应该要先处理那个程序呢?

具有优先级的程序队列图:



我们知道 CPU 一秒钟可以运作多达数 G 的微指令次数,透过核心的 CPU 排程可以让各程序被 CPU 所切换运作,因此每个程序在一秒钟内或多或少都会被 CPU 执行部分的脚本。Linux 给予程序一个所谓的优先执行顺序 (priority, PRI),这个PRI 值越低代表越优先的意思。不过这个 PRI 值是由内核动态调整的,用户无法直接调整 PRI 值的。

# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0  6012  6008  0  80   0 - 28864 do_wai pts/0    00:00:00 bash
0 R     0  7028  6012  0  80   0 - 38314 -      pts/0    00:00:00 ps

由于 PRI 是内核动态调整的,无法去干涉 PRI,可以通过调整 Nice 的值去调整程序的优先执行顺序,就是上面的 NI 值。PRI与NI的相关性如下:
PRI(new)=PRI(old)+Nice

nice 值是有正负的,PRI 越小越早被执行, 所以当nice 值为负值时,就会降低 PRI 值,即是会较优先被处理。

nice 值范围为 -20 ~ 19 ;
root 可随意调整自己或他人程序的 Nice 值;
一般用户仅可条整自己程序的 Nice 值,范围仅为 0 ~ 19 (避免一般用户抢占系统资源);
一般使用者仅可将 nice 值调高,例如本来 nice 为 5 ,只能调整到大于 5;


使用 nice 或 renice 命令调整程序的 nice 值

nice:给予新执行指令新的 nice 值

一般在系统中不重要的程序才需要调大 nice 的值,比如备份工作,由于备份比较消耗资源,调大备份指令的 nice 值,可以使系统的资源分配更为公平。

renice:已运行程序的 nice 重新调整

# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0  6012  6008  0  80   0 - 28864 do_wai pts/0    00:00:00 bash
0 T     0  7720  6012  0  99  19 - 36725 do_sig pts/0    00:00:00 vim
0 R     0  7911  6012  0  80   0 - 38314 -      pts/0    00:00:00 ps

# renice 19 6012
6012 (process ID) old priority 0, new priority 19

# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0  6012  6008  0  99  19 - 28864 do_wai pts/0    00:00:00 bash
0 T     0  7720  6012  0  99  19 - 36725 do_sig pts/0    00:00:00 vim
0 R     0  7921  6012  0  99  19 - 38314 -      pts/0    00:00:00 ps

1.6 /proc 文件系统
 Linux 的 ps、top 命令都是从 /proc 目录读取进程的状态信息,但是它里面的信息却不局限于进程的信息--内核产生的所有状态信息和统计信息也都在 /proc。

进程的信息都分别放到 /proc/[PID] 按 PID 命名的子目录里面。

/proc 目录包含的几个最有用的文件/目录内容信息:

文件/目录

内容

/proc/cmdline

加载 kernel 时下达的相关参数,查看此文件可了解系统启动的一些信息

/proc/meminfo

内存信息

/proc/cpuinfo

cpu 相关信息,包含频率、类型、运算功能等等

/proc/mounts

系统已经挂载的数据,执行 mount 命令直接读取此文件

/proc/modules

已经加载的模块列表(驱动程序)

/proc/[pid]/attr

此目录中的文件提供了用于安全相关模块的 API

/proc/[pid]/cwd

链到进程当前目录的符号链接(软链接)

/proc/[pid]/cmdline

进程的完整命令行

/proc/[pid]/environ

进程的环境变量

/proc/[pid]/exe

链到正在被执行的文件的符号链接

/proc/[pid]/fd

子目录,包含链到每个打开文件的描述符的链接

/proc/[pid]/maps

内存映射信息(共享段、库等)

/proc/[pid]/root

链到进程的根目录(由 chroot 设置)的符号链接

/proc/[pid]/status

进程大量的信息,包含进程的 name、state、ppid 等等

/proc/[pid]/stat

进程的总体状态信息(ps使用这个)



注:man proce 查看更多更详细的 /proc信息

1.7 信号
进程是可以通过信号(signal)控制的,比如重启、关闭、停止进程。

主要的信号代号名称以及内容:

代号

名称

内容

1

SIGHUB

启动被终止的进序,可让该 PID 重新读取自己的配置文件,类似重新启动

2

SIGINT

相当于用键盘输入【ctrl +c】来中断一个程序的进行

9

SIGKILL

强制中断进程,如果该进程运行到一半,那么尚未完成的部分可能会有【半产品】产生,类似 vim 会有 .filename.swp 保留下来

15

SIGTERM

以正常的结束进程来终止该进程,由于是正常的终止,所以后续的动作会将它完成,如果该进程已经发生问题,无法使用正常的终止方法,使用这个也没用

17

SIGSTOP

相当于用键盘输入【ctrl +z】来暂停一个进程




注:更多详细信息可执行 kill -l 或 man 7 signal 命令查看

kill:发送信号

顾名思义,kill 命令最常见的用法是终止一个进程,默认情况下发送 TERM 信号,语法是:

kill [signal] pid

signal 就是要发送信号的编号,没有带信号的编号的kill命令不保证进程会被杀死,因为 TERM 信号可能会被捕获、封锁或忽略。下面的命令:

kill -9 pid

将“保证”进程的消亡,因为是信号 9,即 KILL 不能被捕获到。给“保证”加引号是因为进程的生命力有时候能够变得相当“旺盛”,以致连 kill 9 也不能影响他们(通常是由于有些退化的 I/O 虚假锁定,例如等等已经停止旋转的磁盘)。

重新启动系统通常是解决这些“不听话”进程的唯一方法。

killall 命令可以按照进程的名字杀死所有进程,语法:

killall process_name

1.8 ps:监视进程
ps 用于报告当前系统的进程状态,是最基本同时也是非常强大的进程查看命令,ps 通过读取 /proc 中的虚拟文件来工作。ps 的选项参数众多,只需记住几个常用的选项就可以满足平时查看系统进程 99% 的需要,遇到特殊情况的 1%,不懂的时候使用 man ps 。

常用选项:
-A:显示所有进程,等于 -e 选项
-C:通过名字搜索进程
-f:显示当前用户运行进程的 UID、PID、PPID 等等
f:以 ASCII 字符显示树状结构,表达进程间的相互关系,类似 -H 选项
L:列出栏位相关信息
-l 或 l:采用详细的格式显示当前用户的进程信息
-o:自定义显示进程信息,比如可以根据ps L显示的栏目信息进行自定义输出的进程信息:ps -eo 'tty,comm,pid,ppid,%cpu,%mem',或者根据AIX格式: ps -eo "%p %y %x %c"
-p:列出指定 pid的进程信息,类似 n 选项
-t/t:指定 tty 终端机编号,并列出属于该终端机的程序的状况。比如 ps -t 4 或 ps -t pts/4
-u/-U:列出指定用户的进程信息
x:显示所有程序,不以终端机来区分。

常用命令组合:
查看所有进程信息:
ps -ef
ps aux

查看进程树:
ps -ejH
ps -axjf

查看线程有关的信息:
ps -eLf
ps axms

常用实例

ps axo pid,comm,pcpu     # 查看进程的 PID、名称以及 CPU 占用率
ps aux | sort -rnk 4     # 按内存资源的使用量对进程进行排序
ps aux | sort -nk 3      # 按 CPU 资源的使用量对进程进行排序
ps -u root     # 显示指定用户信息
ps -e -o "%C : %p :%z : %a" | sort -k5 -nr     # 查看进程并按内存使用大小排列
ps -ef     # 显示所有进程信息,连同命令行
ps -ef | grep ssh     # ps 与 grep 常用组合用法,查找特定进程
ps -C nginx     # 通过名字搜索进程
ps aux --sort=-pcpu,+pmem     # CPU或者内存进行排序,-降序,+升序
ps -f --forest -C nginx     # 用树的风格显示进程的层次关系
ps -o pid,ppid,uname,comm -C nginx     # 显示一个父进程的子进程
ps -e -o pid,uname=USERNAME,pcpu=CPU_USAGE,pmem,comm     # 重定义栏目名字
ps -e -o pid,comm,etime     # 显示进程运行的时间
ps -aux | grep named     # 查看named进程详细信息
ps -o command -p 91730 | sed -n 2p     # 通过进程id获取服务名称

字段说明

key

long

description

F

flags

4代表进程的权限位 root;1代表此子进程仅进行复制(fork)而没有实际执行(exec)

S

Stat

进程的状态主要有:R(Running):进程正在运行中或可运行(在队列上);S(Sleep):进程正在睡眠状态(idle),但可以被唤醒(signal);D:不可被唤醒的睡眠状态,进程可能在等待I/O;T:停止状态,背景暂停或调试状态;Z(Zombie):僵尸状态,进程已经被终止但却无法被移除至内存外。

UID

User ID

用户ID

PID

Process ID

进程ID

C

Cpu

cpu 使用率,单位是百分比

PRI

Priority

Priority值

NI

Nice

nice值

ADDR

内存有关

ADDR是kernel function,指出进程在内存的哪个部分,如果是running,一般显示-

SZ

Size

进程使用的内存

WCHAN

WCHAN

进程所在的内核函数的名称,如果进程是多线程则显示*

TTY

controlling tty (terminal)

登录者的终端机位置,若为远程则使用动态端口接口(pts/n)

TIME

TIME

消费CPU运作时间,这里不是系统时间,"[DD-]HH:MM:SS"格式。(别名cputime)。

CMD

COMMAND

触发进程的指令名称

VSZ

VSIZE

进程的虚拟内存大小,单位为KB

RSS

RSS

进程占用的固定内存,单位KB




1.9 top:动态监视进程

ps 命令只能提供系统进程的一次性快照,因此需要使用 top 命令来获得系统正在发生事情的“全景”。

常用 top 选项:
c/-c:显示完整的 Command-line/Program-name
-d:屏幕刷新间隔时间,默认是1秒
 u/-u/U/-U:指定用户名
-p/p:指定进程 pid
-n:循环显示的次数

top 显示 cpu 相关参数说明:
us, user : 用户进程占用cpu百分比
sy, system :内核进程占用cpu百分比
ni, nice :经过改变优先级的用户进程占用cpu百分比
id, idle : 空闲cpu百分比
wa, IO-wait : 等待I/O进程的百分比
hi : time spent servicing hardware interrupts
si : time spent servicing software interrupts
st : time stolen from this vm by the hypervisor

常用 top 交互指令:
f/F: 从当前显示中添加或者删除项目。
l:切换显示平均负载和启动时间信息。
m/M:切换显示内存信息/根据驻留内存大小进行排序。
t:切换显示进程和CPU状态信息。
c:切换显示命令名称和完整命令行。
P:根据CPU使用百分比大小进行排序。
q 退出。

1.10 使用strace来追踪信号和系统调用
有时候通过 ps、top 这样的命令来判断一个进程实际正在做什么相当困难,但通过 strace 命令直接观察一个进程,进程每调用一次系统调用,以及接受到一个信息,这个命令都能显示出来。在 man strace 手册里有其中大多数功能的说明,例如:-f 标准后面跟 fork 出来的进程,这个可以帮助跟踪像 httpd 这个生出好多子进程的守护进程,-e 这个文件选项只显示文件操作,对应找到难以定位的配置文件的位置特别方便。

把 strace 附在正在执行的进程上,监视一会该进程,再从这个进程脱离,从而获取进程的活动信息情况。比如下面是 strace 附在一个活动的 top 进程上获得的信息:
# strace -p PID


在本例中,top 先打开 /proc 目录,用stat获得其信息,然后读取该目录的内容,由此获得当前正在运行的进程清单,top 接着用 stat 获得代表 init 进程的那个目录的信息,然后打开 /proc/1/stat 读取 init 的状态信息。

strace 实践

//编写一个简单的c语言代码test.c
#include <stdio.h>
int main(){
    int a;
    scanf("%d", &a);
    printf("%09d\n", a);
    return 0;
}

//编译后得到可执行文件test,然后使用strace调用执行
# gcc -o test test.c
# ./test    // 直接执行test的结果
68
000000068

# strace ./test   //通过strace执行的结果
execve("./test", ["./test"], [/* 20 vars */]) = 0
brk(NULL)                               = 0x16c9000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4d7e181000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=38904, ...}) = 0
mmap(NULL, 38904, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4d7e177000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20&\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2156160, ...}) = 0
mmap(NULL, 3985888, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4d7db93000
mprotect(0x7f4d7dd56000, 2097152, PROT_NONE) = 0
mmap(0x7f4d7df56000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7f4d7df56000
mmap(0x7f4d7df5c000, 16864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f4d7df5c000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4d7e176000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4d7e174000
arch_prctl(ARCH_SET_FS, 0x7f4d7e174740) = 0
mprotect(0x7f4d7df56000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f4d7e182000, 4096, PROT_READ) = 0
munmap(0x7f4d7e177000, 38904)           = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4d7e180000
read(0, 68
"68\n", 1024)                   = 3
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4d7e17f000
write(1, "000000068\n", 10000000068
)             = 10
exit_group(0)                           = ?
+++ exited with 0 +++

# strace -c ./test    //获取进程所有的系统调用的统计分析
^Cstrace: Process 2009 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         1           read
  0.00    0.000000           0         2           open
  0.00    0.000000           0         2           close
  0.00    0.000000           0         3           fstat
  0.00    0.000000           0         8           mmap
  0.00    0.000000           0         4           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         1           brk
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    25         1 total

1.11 lsof:列出被进程打开的文件
常用选项:
-a:列出打开某文件的进程;
-c<进程名>:列出指定进程所打开的文件;
+D<目录>:递归列出目录下被打开的文件;
-i<条件>:列出符合条件的进程(4、6、协议、:端口、 @ip);
-p<进程号>:列出指定进程号所打开的文件;
-u:列出UID号进程详情;

lsof 实例

# lsof -i    // 显示所有连接
COMMAND     PID   USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
sshd       2808   root    3u  IPv4 89562037      0t0  TCP web:22999->225.0.0.115:freeoaserver (ESTABLISHED)
sshd       2816  david    3u  IPv4 89562037      0t0  TCP web:22999->225.0.0.115:freeoaserver (ESTABLISHED)
......

# lsof -i 6    // 显示ipv6连接
COMMAND   PID   USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
master   5880   root   14u  IPv6 52188842      0t0  TCP VM_0_13_centos:smtp (LISTEN)
chronyd 32061 chrony    6u  IPv6  3289514      0t0  UDP VM_0_13_centos:323
.......

# lsof -iTCP    //显示tcp连接
COMMAND     PID  USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
sshd       2808  root    3u  IPv4 89562037      0t0  TCP web:22999->225.73.55.115:freeoaserver (ESTABLISHED)
sshd       2816 david    3u  IPv4 89562037      0t0  TCP web:22999->225.73.55.115:freeoaserver (ESTABLISHED)
taskmgr    3317  root    0u  IPv4 89581455      0t0  TCP web:53644->103.117.121.93:6677 (SYN_SENT)
master     5880  root   13u  IPv4 52188841      0t0  TCP VM_0_13_centos:smtp (LISTEN)
master     5880  root   14u  IPv6 52188842      0t0  TCP VM_0_13_centos:smtp (LISTEN)
sshd       8673  root    3u  IPv4 89580550      0t0  TCP web:22999->225.73.55.115:3comfaxrpc (ESTABLISHED)......

# lsof -i:80    // 显示监听80端口相关的进程信息
COMMAND   PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
nginx   23008 root    8u  IPv4 56706878      0t0  TCP *:http (LISTEN)
nginx   23009  www    8u  IPv4 56706878      0t0  TCP *:http (LISTEN)

# lsof -i@225.0.0.115    // 显示指定主机连接的进程信息
COMMAND   PID  USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
sshd     2808  root    3u  IPv4 89562037      0t0  TCP web:22999->225.73.55.115:freeoaserver (ESTABLISHED)
sshd     2816 david    3u  IPv4 89562037      0t0  TCP web:22999->225.73.55.115:freeoaserver (ESTABLISHED)
sshd     8673  root    3u  IPv4 89580550      0t0  TCP web:22999->225.73.55.115:3comfaxrpc (ESTABLISHED)
sshd     8676 david    3u  IPv4 89580550      0t0  TCP web:22999->225.73.55.115:3comfaxrpc (ESTABLISHED)
nginx   23009   www    3u  IPv4 89582028      0t0  TCP web:http->225.73.55.115:fjhpjp (ESTABLISHED)

# lsof  -i -sTCP:ESTABLISHED    // 显示tcp连接的进程信息
COMMAND     PID  USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
sshd       2808  root    3u  IPv4 89562037      0t0  TCP web:22999->225.73.55.115:freeoaserver (ESTABLISHED)
sshd       2816 david    3u  IPv4 89562037      0t0  TCP web:22999->225.73.55.115:freeoaserver (ESTABLISHED)
sshd       8673  root    3u  IPv4 89580550      0t0  TCP web:22999->225.73.55.115:3comfaxrpc (ESTABLISHED)
sshd       8676 david    3u  IPv4 89580550      0t0  TCP web:22999->225.73.55.115:3comfaxrpc (ESTABLISHED)
nginx     23009   www    3u  IPv4 89582028      0t0  TCP web:http->225.73.55.115:fjhpjp (ESTABLISHED)
freeoa 25863  root    6u  IPv4 64551180      0t0  TCP web:51422->169.254.0.55:lsi-bobcat (ESTABLISHED)

# lsof -u david    //显示指定用户打开的文件
COMMAND  PID  USER   FD   TYPE             DEVICE  SIZE/OFF     NODE NAME
sshd    2816 david  cwd    DIR              253,1      4096        2 /
sshd    2816 david  rtd    DIR              253,1      4096        2 /
sshd    2816 david  txt    REG              253,1    852856    16203 /usr/sbin/sshd
sshd    2816 david  mem    REG              253,1     37168    16740 /usr/lib64/libnss_sss.so.2
sshd    2816 david  mem    REG              253,1     15480     8530 /usr/lib64/security/pam_lastlog.so
......

# kill -9 `lsof -t -u david`    // 杀死指定用户运行的进程

# lsof -c nginx    // 列出指定进程打开的文件
COMMAND   PID USER   FD      TYPE             DEVICE SIZE/OFF     NODE NAME
nginx   23008 root  cwd       DIR              253,1     4096   919161 /data/application/nginx-1.16.0/conf/vhosts
nginx   23008 root  rtd       DIR              253,1     4096        2 /
nginx   23008 root  txt       REG              253,1  7299448   919146 /data/application/nginx-1.16.0/sbin/nginx
nginx   23008 root  mem       REG              253,1    61624    21247 /usr/lib64/libnss_files-2.17.so
nginx   23008 root  mem       REG              253,1   155784     4428 /usr/lib64/libselinux.so.1
nginx   23008 root  mem       REG              253,1   105824    21252 /usr/lib64/libresolv-2.17.so
......
# lsof -p 23009    //列出指定进程号打开的文件
COMMAND   PID USER   FD      TYPE             DEVICE SIZE/OFF     NODE NAME
nginx   23009  www  cwd       DIR              253,1     4096   919161 /data/application/nginx-1.16.0/conf/vhosts
nginx   23009  www  rtd       DIR              253,1     4096        2 /
nginx   23009  www  txt       REG              253,1  7299448   919146 /data/application/nginx-1.16.0/sbin/nginx
nginx   23009  www  mem       REG              253,1    37168    16740 /usr/lib64/libnss_sss.so.2
nginx   23009  www  mem       REG              253,1    61624    21247 /usr/lib64/libnss_files-2.17.so
nginx   23009  www  mem       REG              253,1   155784     4428 /usr/lib64/libselinux.so.1
nginx   23009  www  mem       REG              253,1   105824    21252 /usr/lib64/libresolv-2.17.so
nginx   23009  www  mem       REG              253,1    15688     4556 /usr/lib64/libkeyutils.so.1.5
nginx   23009  www  mem       REG              253,1    67104    16148 /usr/lib64/libkrb5support.so.0.1
......

注:lsof 真的很强大!

1.12 其它
pidof:查找正在运行进程的 pid

# pidof nginx
2309 2308
# pidof systemd
1
# pidof sshd
8676 8673 2816 2808

程序 program、进程 process、线程 thread 之间的关系和区别

简单来说,程序是一个可执行的文件,是一组指令的集合,比如一个 windows 的谷歌浏览器安装文件 chrom.exe 或 shell 脚本 auto-install.sh

进程就是一个正在运行的程序,执行者的权限属性、程序的程序代码所需数据等都会被加载内存中, 操作系统给予这个内存内的单元一个标识符 (PID)。

线程是一个进程执行一次 fork 的结果,线程继承了包含它的进程的很多属性(例如,进程的地址空间),多个线程在同一个进程内按照一种称为多线程的机制并发执行。



线程与进程之间的区别

进程不共享其地址空间,而在同一进程下执行的线程共享地址空间。

进程是相互独立执行的,进程之间的同步仅由内核负责,而另一方面,线程同步必须由线程在其下执行的进程负责。

与进程之间的上下文切换相比,线程之间的上下文切换速度更快。

两个进程之间的交互只能通过标准的进程间通信来实现,而在同一进程下执行的线程可以轻松进行通信,因为它们共享大多数资源,例如内存,文本段等。

一个程序至少有一个进程,一个进程至少有一个线程。进程是程序的一部分,线程是进程的一部分。



该文章最后由 阿炯 于 2021-03-11 22:22:39 更新,目前是第 2 版。