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进程,杀死它可能导致系统重启。

posted on 2024-08-27 16:52  jiayou111  阅读(156)  评论(0编辑  收藏  举报