引言
在Linux
系统下top
命令是一个查看cpu
使用率的一个重要的命令,今天我们就来说说这个重要的命令;
1.top命令显示解析
在Linux
终端下输入top
就会产生动态的cpu
使用情况的图表,现在我们来一个一个解释上图中显示的是什么东西;
top - 19:45:03 up 54 min, 1 user, load average: 0.79, 0.82, 3.17
第一个时间19:45:03
表示当前时间;
54min
表示cpu
运行了多少时间,简单来说就是开始多久了;
1 user
表示当前有一个用户;
关于这个load average
表示平均负载,这个我们后面详细介绍;
Tasks: 238 total, 1 running, 237 sleeping, 0 stopped, 0 zombie
Tasks
表示任务;(这里的任务可以理解为进程)
238 total
表示当前总共有238
个任务;
1 running
表示现在有一个任务是在运行中的
237 sleeping
表示睡眠进程数
0 stopped
表示停止进程数,这个表示被中断的进程,比如正在gdb
调试中的程序;
0 zombie
表示僵尸进程数量,这些在后面都会讲解;
%Cpu(s): 14.6 us, 0.7 sy, 0.0 ni, 84.4 id, 0.2 wa, 0.0 hi, 0.1 si, 0.0 st
这一行表示了cpu
的使用情况;
14.6 us
表示用户使用cpu
占比;
0.7 sy
表示内核使用cpu
占比;
84.4 id
表示空闲cpu
占比;
上述三个加起来应该是1
也就是100%
在cpu
被最大限度使用时,用户使用和内核使用加起来是100%
,此时空闲cpu
为0
0.0 ni
表示用户改过优先级的进程占多少;
0.2 wa
表示待输入输出的cpu
占比
0.0 hi
表示硬中断cpu
占比
0.0 si
表示软中断cpu
占比
0.0 st
表示虚拟机占比
MiB Mem : 7746.9 total, 5404.9 free, 1177.0 used, 1164.9 buff/cache
7746.9 total
—物理内存总量
5404.9 free
----空闲内存
1177.0 user
----正在使用的内存
1164.9 buff/cache
—作为内核缓存的内存量
MiB Swap: 4096.0 total, 4096.0 free, 0.0 used. 5896.5 avail Mem
4096.0 total
—交换区总量
4096.0 free
—空闲交换区总量
0.0 used
—使用交换区总量
5896.5 avail Men
—可用于进程下一次分配的物理内存数量
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
PID
—进程id
USER
—进程所有者的用户名
PR
—优先级(数字越小优先级越高)
NI
—优先级
关于NI
和PR
的区别我们将在后面讲解
VIRT
—进程使用的虚拟内存总量
RES
—进程使用的未被换出的物理内存大小
SHR
—共享内存大小
S
—进程状态(D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程)
%CPU
—CPU占用百分比
%MEM
—进程使用的物理内存百分比
TIME+
—进程使用的时间单位毫秒
COMMAND
—命令名
2.僵尸进程
简单来说就是子进程已经死了但是父进程还在运行,而且父进程没有回收子进程,此时子进程就会变成僵尸进程;
#include <unistd.h>
#include <stdio.h>
int main()
{
int pid;
pid = fork();
if (pid == 0) {
} else {
while (1) {
}
}
return 0;
}
我们现在将这个进程丢到后台执行;
我们通过执行ps
命令就可以看到我们正在运行的进程;
我们可以看到10111
是我们运行程序的进程id而下面的10112
是该进程创建的子进程id;在这个进程后面有一个<defunct>
这个就表示这个进程现在是个僵尸进程;
接着我们看一下top
此时的情况:
我们可以看到第一行的负载增加了;
第二行zombie
变成了一个,那个就是我们创建的僵尸进程;
而且现在有两个进程正在运行,其中一个就是我们的a.out
;
我们在图片的最后一行可以看到关于我们这个进程的信息,因为只有他一个程序在跑,所以这个进程占用的cpu
很高;
那我们能不能找到那个僵尸进程呢,是可以的
我们可以看到僵尸进程是没有内存的,而且在进程状那里变成了Z
,就表示该进程是一个僵尸进程;
3.ctrl+z处理进程和停止进程
现在有一个这样的程序
#include <stdio.h>
int main()
{
while (1) {
}
return 0;
}
我们来执行一下他然后ctrl+z
掉这个进程;
现在我们在top
中观察一下
我们可以发现多了一个停止的进程;我们在下面来找一下这个进程;
这个进程是T
表示一个停止的进程;
我们现在获得了这个进程的ID那我们尝试kill
掉这个进程
我们发现还是有一个停止中的进程;
我发现这个进程并没有被kill
掉;
于是我们使用一个暴力的手段kill -9 (进程号)
;
这下这个ctrl+z
的进程终于被kill
掉了;
3.1kill 和 kill -9
kill
命令的格式是
kill -Signal pid
默认情况下是15
;
默认参数下,kill
发送SIGTERM(15)
信号给进程,告诉进程,你需要被关闭,请自行停止运行并退出;
刚才我们在kill
被ctrl+z
的进程时失败,可能是因为他已经是一个停止的进程了;
相比kill -15
,kill -9
就暴力很多了;
kill -9
发送SIGKILL
信号给进程,告诉进程,你被终结了,请立刻退出;
TERM(或数字9)
表示“无条件终止”;
因此kill - 9
表示强制杀死该进程,与SIGTERM
相比,这个信号不能被捕获或忽略,同时接收这个信号的进程在收到这个信号时不能执行任何清理;
3.2其他的停止程序的方法
我们在这里演示一个最常见的gdb
;
然后我们重开一个终端,执行top
命令;
我们可以看到出来了一个停止的进程;
我们在下面来找一下这个进程;
我们可以看到被gdb
中断的进程的状态是t
;
同样的这个进程不能被普通kill
掉;
我们会发现,他被kill
以后变成了一个僵尸进程;
在另一个终端下执行的gdb
,我们执行一下n
命令
我们会发现这个已经运行不了了;那现在我们让这个程序重新运行一下;
然后我们来看一下这边的top
我们发现他重新变成了一个停止的进程;
4.孤儿进程
什么是孤儿进程?
我们这里和僵尸进程做一个区别;
僵尸进程是父进程一直运行,子进程死掉后父进程没有回收,子进程就会变成僵尸进程;
孤儿进程就是子进程一直在运行,但是父进程已经死了;然后他被init
这个进程收养;
我们先来看一个正常的进程;(父子进程都在运行的)
#include <unistd.h>
#include <stdio.h>
int main()
{
int pid;
pid = fork();
if (pid == 0) {
while (1) {
}
} else {
while (1) {
}
}
return 0;
我们运行一下这个程序,然后用pstree
这个命令来看一下;
我们可以在这个图片的最下面看到在一个终端下运行着我们的a.out
这个程序创建了一个进程,我们就可以看到这样的关系;
那现在如果父进程死掉,会怎么样;
#include <unistd.h>
#include <stdio.h>
int main()
{
int pid;
pid = fork();
if (pid == 0) {
while (1) {
}
} else {
}
return 0;
}
我们可以看到这个子进程被systemd
这个进程收养了;
此时这个子进程我们叫做孤儿进程;
我们上面说到孤儿进程是被init
这个进程收养的,那为什么现在变成了systemd
呢?
其实这里的systemd
就是init
;我们可以看到他是所有进程的父进程;
我试过kill
掉这个进程但是哪怕是kill -9
都杀不掉这个进程;
4.1关于终端进程
在刚才测试孤儿进程的时候我发现了,我每打开一个终端就是一个进程;
那我如果kill
掉终端这个进程会怎么样;
我们先查一下终端进程的id;
使用我们的top
命令,我们就能找到一个COMMAND
为deepin-terminal
的进程我们在kill
掉这个进程以后我们的终端就关闭了;
关于NI
和PR
还有负载,我将重新写一篇博客;