1.基础
1.1什么是进程
开发写的代码我们称为程序,那么将开发的代码运行起来。我们称为进程。总结一句话就是:当我们运行一个程序,那么我们将运行的程序叫进程。
1.当程序运行为进程后,系统会为该进程分配内存,以及进程运行的身份和权限。
2.在进程运行的过程中,系统会有各种指标来表示当前运行的状态。
1.2程序和进程的区别
1.程序是数据和指令的集合,是一个静态的概念。
比如/bin/ls
、/bin/cp
等二进制文件。同时程序可以长期存在系统中。
2.进程是程序运行的过程,是一个动态的概念。
进程是存在生命周期的概念的,也就是说进程会随着程序的终止而销毁,不会永久运行在系统中。
1.3进程的生命周期
1.3.1进程生命周期图
1.3.2进程生命流程说明
当父进程接收到任务调度时,会通过fork派生子进程来处理,那么子进程会继承父进程属性。
1.子进程在处理任务代码时,父进程其实不会进入等待,其运行过程是由linux系统进行调度的。
2.子进程在处理任务代码后,会执行退出,然后唤醒父进程来回收子进程的资源。
3.如果子进程在处理任务代码过程中异常退出,而父进程却没有回收子进程资源,会导致子进程虽然运行实体已经消失,但仍然在内核的进程表中占据一条记录,长期下去对于系统资源是一个浪费。(僵尸进程)
4.如果子进程在处理任务过程中,父进程退出了,子进程没有退出,那么这些子进程就没有父进程来管理了,由系统的system进程(init进程,即pid=1的进程)管理。(孤儿进程)
PS:每个进程都父进程的PPID,子进程则叫PID。
1.4僵尸进程与孤儿进程区别
我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程再创建新的进程。任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。
-
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
-
僵尸状态:是一个比较特殊的状态,当进程退出父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会在以终止状态保持在进程表中,并且会一直等待父进程读取退出状态代码。
-
僵尸进程与孤儿进程的区别:
孤儿进程是子进程还在运行,而父进程挂了,子进程被init进程收养。僵尸进程是父进程还在运行但是子进程挂了,但是父进程却没有使用wait()或waitpid()来清理子进程的进程信息,导致子进程虽然运行实体已经消失,但是仍然在内核的进程表中占据一条记录,这样长期下去对于系统资源是一个浪费。僵尸进程将会导致资源浪费,而孤儿则不会。
那么如何避免僵尸进程呢?
- 1.fork两次
原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。 - 2.通过信号机制
子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait()或waitpid()进行处理僵尸进程。
2.监控进程状态
2.1静态查看进程
2.1.1ps命令
[root@devops03 ~]# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 117464 5696 ? Ss 2023 268:08 /usr/lib/systemd/systemd --system --deserialize 22
root 2 0.0 0.0 0 0 ? S 2023 0:02 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 2023 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< 2023 0:00 [rcu_par_gp]
root 6 0.0 0.0 0 0 ? I< 2023 0:00 [kworker/0:0H-kb]
root 8 0.0 0.0 0 0 ? I< 2023 0:00 [mm_percpu_wq]
root 9 0.0 0.0 0 0 ? S 2023 0:22 [ksoftirqd/0]
root 10 0.0 0.0 0 0 ? I 2023 121:11 [rcu_sched]
USER 启动进程的用户
PID 进程运行的ID号
%CPU 进程占用CPU百分比
%MEM 进程占用内存百分比
vSz 进程占用虚拟内存大小(单位KB)
RSS 进程占用物理内存实际大小(单位KB)
TTY 进程是由哪个终端运行启动的tty1、pts/O等 ?表示内核程序与终端无关
STAT 进程运行过程中的状态 man ps (/STATE)
START 进程的启动时间
TIME 进程占用CPU的总时间(为0表示还没超过秒)
COMMAND 程序的运行指令,[方括号]属于内核态的进程。没有[]的是用户态进程。
2.1.2STAT状态含义
[root@devops03 ~]# ps -aux|awk -F ' ' '{print $8}'|sort|uniq -c|sort -k1 -nr
49 S
34 I<
22 Sl
20 Ss
11 I
6 Ssl
4 Ss+
3 S+
2 SN
1 STAT
1 S<sl
1 R+
1 D+
1 D
STAT基本状态 描述 STAT状态+符号 描述
R 进程运行 s 进程是控制进程,Ss进程的领导者,父进程
S 可中断睡眠 < 进程运行在高优先级上,S<优先级较高的进程
T 进程被暂停 N 进程运行在低优先级上,SN优先级较低的进程
D 不可中断进程 + 当前进程运行在前台,R+该表示进程在前台运行
Z 僵尸进程 | 进程是多线程的,SI表示进程是以线程方式运行
2.2动态查看进程
2.2.1top命令
[root@devops03 ~]# top
top - 16:27:04 up 293 days, 23:59, 3 users, load average: 1.00, 1.02, 1.02
Tasks: 151 total, 1 running, 105 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.5 us, 1.5 sy, 0.0 ni, 97.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8143308 total, 2902452 free, 1965208 used, 3275648 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 5499824 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18470 root 20 0 58836 4080 3420 R 6.2 0.1 0:00.01 top
1 root 20 0 117464 5696 4040 S 0.0 0.1 268:08.40 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:02.06 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp
6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H-kb
8 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq
9 root 20 0 0 0 0 S 0.0 0.0 0:22.17 ksoftirqd/0
10 root 20 0 0 0 0 I 0.0 0.0 121:12.04 rcu_sched
11 root rt 0 0 0 0 S 0.0 0.0 2:55.28 migration/0
13 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/0
14 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/1
2.2.2top常用按键显示介绍
字母 含义
h 查看帮助
1 数字1,显示所有CPU核心的负载
z 以高亮显示数据
b 高亮显示处于R状态的进程
M 按内存使用百分比排序输出
P 按CPU使用百分比排序输出
q 退出top
2.2.3top每列含义详解
[root@devops03 ~]# top
top - 16:27:04 up 293 days, 23:59, 3 users, load average: 1.00, 1.02, 1.02
Tasks: 151 total, 1 running, 105 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.5 us, 1.5 sy, 0.0 ni, 97.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8143308 total, 2902452 free, 1965208 used, 3275648 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 5499824 avail Mem
Tasks: 151 total 当然进程的总数
1 running 正在运行的进程数
105 sleeping 睡眠的进程数
0 stopped 停止的进程数
0 zombie 僵尸进程数
%Cpu(s): 1.5 us 系统用户进程使用CPU百分比
1.5 sy 内核空间中的进程占用CPU百分比,通常内核是于硬件进行交互
97.0 id 空闲CPU的百分比
0.0 wa CPU等待IO完成的时间
0.0 hi 硬中断,占的CPU百分比
0.0 si 软中断,占的CPU百分比
0.0 st 比如虚拟机占用物理CPU的时间
2.2.4什么是系统中断
详见另一篇文章
3.进程状态切换-实战
3.1示例1-进程状态切换
3.1.1终端1-vi操作
vim test
3.1.2终端2-查看进程状态-S+
S 表示睡眠模式
+ 表示前台运行
[root@devops03 ~]# ps aux | grep test | grep -v grep
root 19871 0.0 0.0 44244 7436 pts/3 S+ 16:38 0:00 vim test
3.1.3终端1-挂起操作
[root@devops03 ~]# vim test
[1]+ Stopped vim test
3.1.4终端2-查看进程状态-T+
T 表示停止
[root@devops03 ~]# ps aux | grep test | grep -v grep
root 19871 0.0 0.0 44244 7436 pts/3 T 16:38 0:00 vim test
3.2示例2-不可中断进程
3.2.1使用tar打包文件时,可以通过终端不断查看状态,由S+,R+、D+
S+ 表示可中断睡眠,在前台运行
[root@devops03 ~]# ps -aux | grep etc.tar | grep -v grep
root 2843 17.0 0.1 124580 2292 pts/0 S+ 14:22 0:03 tar czvf etc.tar.gz /etc/ /usr/ /var/
R+ 表示进程运行,在前台运行
[root@devops03 ~]# ps -aux | grep etc.tar | grep -v grep
root 2843 17.5 0.1 124672 2380 pts/0 R+ 14:22 0:03 tar czvf etc.tar.gz /etc/ /usr/ /var/
D+ 不可中断进程,在前台运行
[root@devops03 ~]# ps -aux | grep etc.tar | grep -v grep
root 2843 17.5 0.1 124672 2380 pts/0 D+ 14:22 0:03 tar czvf etc.tar.gz /etc/ /usr/ /var/
3.3示例3-僵尸进程
3.3.1安装gcc编译器
yum install gcc -y
3.3.2准备C语言代码
cat >zombie_test.c<<'EOF'
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
pid_t pid;
pid = fork();
if (pid==0) {
int iPid =(int)getpid();
fprintf(stderr,"子进程,%d\n",iPid);
sleep(1);
fprintf(stderr,"Child exits\n");
return EXIT_SUCCESS;
}
int iPid = (int)getpid();
fprintf(stderr,"父进程,%d\n",iPid);
fprintf(stderr,"sleep....\n");
sleep(360);
fprintf(stderr,"parent exits\n");
return EXIT_SUCCESS;
}
EOF
3.3.3编译程序
[root@devops03 ~]# gcc zombie_test.c -o zombie_test
[root@devops03 ~]# ll zombie_test*
-rwxr-xr-x 1 root root 12416 Aug 27 16:44 zombie_test
-rw-r--r-- 1 root root 522 Aug 27 16:44 zombie_test.c
3.3.4运行程序
[root@devops03 ~]# ./zombie_test
父进程,20759
sleep....
子进程,20760
Child exits
# 此时子进程,运行退出
3.3.5查询进程状态
[root@devops03 ~]# ps aux | grep test | grep -v grep
root 20759 0.0 0.0 4148 776 pts/3 S+ 16:46 0:00 ./zombie_test
root 20760 0.0 0.0 0 0 pts/3 Z+ 16:46 0:00 [zombie_test] <defunct> # 此时发现子进程已经是僵尸进程了
3.3.6kill僵尸进程,发现kill不掉
[root@devops03 ~]# ps aux | grep test | grep -v grep
root 20759 0.0 0.0 4148 776 pts/3 S+ 16:46 0:00 ./zombie_test
root 20760 0.0 0.0 0 0 pts/3 Z+ 16:46 0:00 [zombie_test] <defunct>
3.3.7只能kill掉主进程,让僵尸进程变为孤儿进程,由init进程进行接管回收
[root@devops03 ~]# kill -9 20759
[root@devops03 ~]# ps aux | grep test | grep -v grep
找到僵尸进程的父进程,kill掉父进程,那么僵尸进程将变为孤儿进程,孤儿进程在系统中由init进程接管,init进程将回收僵尸进程的资源;
或者reboot系统,因为僵尸进程不会被杀死。
查找僵尸进程的父进程的命令:
ps -A -ostat,pid,ppid | grep -e '[zZ]'
另外需要特别注意的是,杀死父进程可能会影响到父进程的其他子进程,因此在执行这一操作前需要谨慎考虑。如果父进程是系统关键进程,如PID为1的init进程,杀死它可能导致系统重启。