进程管理

进程管理

进程介绍

程序:存放代码的文件=》静态

进程:程序运行的过程=》动态

  • 描述方式1:程序的运行过程

  • 描述方式2:操作系统控制着硬件去运行程序的过程

  • PS:进程是操作系统最核心的概念

    • 并发:多个任务看起来是同时运行的即可

    • 并行:多个任务是真正的同时运行 只有多核才能实现并行

    • 强调:cpu是运行代码,不是做io的

线程:进程内代码的执行过程 线程才是cpu上的执行单位 一个进程内至少有一个线程

  • 一个进程的多个线程共享该进程的内存资源,不同进程的多个线程的内存资源互相隔离

提交任务的方式:

  • 同步:提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行

  • 异步:提交完一个任务之后,不在原地等待,结果直接执行下一行代码,会导致任务是并发执行的

注意:

  • 1.当程序运行为进程后,系统会为该进程分配内存,以及运行的身份和权限。

  • 2.在进程运行的过程中,服务器上回有各种状态来表示当前进程的指标信息。

同一程序可能对应多个进程

  • 父进程:程序运行时对产生的第一个进程

  • 子进程:有父进程衍生fork()出来的进程

  • 注意:如果父进程终止,子进程也会随之被终止

进程之间的状态(R、S、D、T、Z、X)

  • R- -可执行状态(运行状态)

    • 只有运行状态的进程才有可能在CPU上运行,注意的是可能,并不意味着进程一定在运行中。同一时刻可能有多个进程处在可执行状态,这些进程的PCD (进程控制块) 被放入对应CPU 的可执行队列中。然后进程调度器从各个可执行队列中分别选择一个进程在CPU 上运行。

      另外如果计算机只有一个处理器, 那么一次最多只有一个进程处于这种状态。

  • S- -可中断睡眠状态(sleeping)

    • 处在这个状态意味着进程在等待事件完成。这些进程的PCB (task struct结构) 被放入对应时间的等待队列中。然后等待的事件发生时, 对应的进程将被唤醒。

  • D- -不可中断睡眠(disk sleep)

    • 在这个状态的进程通常会等待I0 的结束。

      这个状态与sleeping状态相似, 处于睡眠状态, 但是此刻进程是不可中断的, 意思是不响应异步信号。另外你会发现处在D状态的进程kill - 9竟然也杀不死。这就相当于我们怎么也叫不醒一个装睡的人。

  • T- -暂停状态

    • 给进程发送一个sIGsm0P 信号, 进程就会响应信号进入m状态, 除非该进程正处在D状态。再通过发送sIGc0Nm 信号让进程继续运行。

      kill - sIGsm0P

      kill - sIGc0Nm

  • Z- -僵尸状态

    • 僵死状态是一个比较特殊的状态。进程在退出的过程中, 处于mAsK DEAD状态。

      在这个退出过程中, 进程占有的所有资源将被回收, 除了task struct结构 (以及少数资源) 以外。于是进程就只剩下task struct这么个空壳, 故称为僵尸。

      u- - 死亡状态或退出状态 (dead)

      死亡状态是内核运行 kernel /exit.c 里的 do exit( ) 函数返回的状态。这个状态只是一个返回状态, 你不会在任务列表里看到这个状态

进程状态切换

任务的三种运行状态

未命名文件

  • 就绪状态

    • 当进程已分配到除CPU 以外的所有必要的资源, 只要获得处理机便可立即执行, 这时的进程状态称为就绪状态。

  • 运行态(执行状态)Runing

    • 当进程已获得处理机, 其程序正在处理机上执行, 此时的进程状态称为执行状态

  • 阻塞态((Blocked)

    • 正在执行的进程, 由于等待某个事件发生而无法执行时, 便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种, 例如, 等待I/0完成、申请缓冲区不能满足、等待信件( 信号)等。

  • 就绪态=》运行态

    • 就绪态抢到CPU资源时转换为运行态

  • 运行态=》就绪态

    • 运行态在失去CPU资源时进入就绪态

  • 运行态=》阻塞态

    • 运行态在进行IO操作时进入阻塞态

  • 阻塞态=》就绪态

    • 阻塞态在读写完IO后转换为就绪态

查看进程

ps aux, 查看进程用户、PID、占用百分比、占用内存百分比、状态、执行的命令等
[root@localhost ~]# ps aux 
a:显示一个终端的所有进程
u:选择有效的用户ID或者是用户名
x:显示没有控制终端的进程,同时显示各个命令的具体路径

示例

[root@instance-lpbn3wlc ~]# ps aux |head -5
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.2  95140 11120 ?        Ss   Nov01   0:22 /usr/lib/systemd/systemd --system --deserialize 20
root           2  0.0  0.0      0     0 ?        S    Nov01   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        I<   Nov01   0:00 [rcu_gp]
root           4  0.0  0.0      0     0 ?        I<   Nov01   0:00 [rcu_par_gp]
  • 在多任务处理操作系统中,每个CPU(或核心)在一个时间点上只能处理一个进程。

  • 在进程运行时,它对 CPU 时间和资源分配的要求会不断变化,从而为进程分配一个状态,它随着环境要求而改变

查看结果显示

image-20201103184731505

USER:       //启动程序的用户
PID:        //进程ID
%CPU:       //CPU占用率
%MEM:       //内存占用率
VSZ:        //占用虚拟内存,单位:kb(killobytes)
  Vsx是指已分配的线性空间大小, 这个大小通常并不等于程序实际用到的内存大小, 产生这
个的可能性很多
比如内存映射, 共享的动态库, 或者向系统申请了更多的堆, 都会扩展线性空间大小。
RSS:        //占用实际内存,单位:kb(killobytes)
Rsx是Resident set siye, 常驻内存大小, 即进程实际占用的物理内存大小

TTY:        //进程运行的终端
       ?:      #内核运行的终端
       tty1:   #机器运行的终端
       pts/0:  #远程连接的终端

STAT:       //进程状态   man ps (/STATE)
       D:      #不可中断睡眠, 即在睡眠的过程中不可以接收信号唤醒=》执行的I0操作得不到硬件设备的响应
       R:      #正在运行的状态
       S:      #可中断睡眠 sleep, 即在睡眠的过程中可以接收信号唤醒=》执行的I0操作可以得到硬件设备的响应
       T:      #停止的进程
       W:      #进入内存交换(从内核2.6开始无效)
       X:      #死掉的进程(几乎看不见,因为死了就立即回收了)
       Z:      #僵尸进程
       <:      #优先级高的进程
       N:      #优先级较低的进程
       L:      #有些页被锁进内存
       s:      #父进程(在它之下有子进程开启着)
       l:      #小写字母l , 代表以线程的方式运行, 即多线程
       |:      #管道符号代表多进程
       +:      #该进程运行在前台
START:      //进程的启动时间
TIME:       //进程占用CPU的总时间
COMMAND:    //进程文件,进程名
      []:     #内核态的进程
       没[]:    #用户态的进程

linux进程有两种睡眠状态

# 1、Interruptible sleep (可中断睡眠, 在ps命令中显示" s" )
处在这种睡眠状态的进程是可以通过给它发送signal来唤醒的, 比如发HUP 信号给nginx的master进程可以让nginx重新加载配置文件而不需要重新启动nginx进程;
# 2、Uninterruptible sleep (不可中断睡眠, 在ps命令中显示"D" )
处在这种状态的进程不接受外来的任何signal, 这也是为什么之前我无法用kill 杀掉这些处于D状态的进程, 无论是"kill " "kill - 9""kill - 15" 还是按 ctrl +c 、ctrl +x 都无济于, 因为它们压根儿就不受这些信号的支配。

# 解释
进程为什么会被置于D状态呢? 处于uninterruptible sleep状态的进程通常是在等待I0 , 比如磁盘I0 , 网络I0 , 其他外设I0 , 如果进程正在等待的I0 在较长的时间内都没有响应, 那么就很会不幸地被ps 看到了, 同时也就意味着很有可能有I0 出了问题, 可能是外设本身出了故障, 也可能是比如NFS挂载的远程文件系统已经不可访问了。

正是因为得不到I0 的响应, 进程才进入了uninterruptible sleep状态, 所以要想使进程从uninterruptible  sleep状态恢复, 就得使进程等待的I0 恢复, 比如如果是因为从远程挂载的NPs 卷不可访问导致进程进入uninterruptible   sleep状态的, 那么可以通过恢复该NPs 卷的连接来使进程的I0 请求得到满足, 除此之外, 要想干掉处在D状态进程就只能重启整个工inux 系统了 (恐怖的D状
态)

看到有人说如果要想杀掉D状态的进程, 通常可以去杀掉它的父进程 (通常是shell , 我理解的这种情况是在shell 下直接运行的该进程, 之后该进 程转入了D状态) , 于是我就照做了, 之后就出现了上面的状态: 他们的父进程被杀掉了, 但是他们的父进程PID 都变成了1 , 也就是init进程, 这下可如何是好? 此时我这些D状态的进程已经影响到其他一些进程的运行, 而已经无法访问的NPs 卷又在段时间内无法恢复, 那么, 只好重新启动了。

# 强调
D与x状态的进程都无法用kill - 9杀死

示例1:PS命令查看前台进程转换到停止

#在终端上运行vim
[root@zls ~]# vim zls.txt

#查看vim运行的状态,S:睡眠状态 +:在前台运行
[root@zls ~]# ps aux|grep [v]im
root       1306  0.0  0.2 151664  5180 pts/0    S+   13:00   0:00 vim zls.txt

#执行ctrl + z,将进程放置后台
[1]+  已停止               vim zls.txt

#进程状态变成了T,暂停或被追踪的状态
[root@zls ~]# ps aux|grep [v]im
root       1306  0.0  0.2 151664  5180 pts/0    T    13:00   0:00 vim zls.txt

案例二:PS命令查看不可中断状态

# 1.在窗口1执行命令
[root@egon ~]# tar cvzf egon.tar.gz /etc/ /usr/ /var/ /usr/
# 2.在窗口2查看tar的状态:S+、R+、D
[root@egon ~]# while true;do ps aux |grep [t]ar;sleep 0.3;clear;done

案列三:查看进程优先级(nice好心值)

#nice     好心值
#好心值越低,优先级越高,好心值越高,优先级越低。范围-20~ +19[root@instance-lpbn3wlc ~]# nice -n -20 sleep 3000 &[1] 130188
[root@instance-lpbn3wlc ~]# nice -n 19 sleep 3000 &
[2] 130201
[root@instance-lpbn3wlc ~]# ps aux | grep sleep
root      130188  0.0  0.0   7280   772 pts/1    S<   20:34   0:00 sleep 3000
root      130201  0.0  0.0   7280   836 pts/1    SN   20:34   0:00 sleep 3000
root      130239  0.0  0.0  12108  1064 pts/1    S+   20:35   0:00 grep --color=auto sleep
       
[root@instance-lpbn3wlc ~]# nice -n 16 sleep 9000 &
[3] 130303
[root@instance-lpbn3wlc ~]# ps aux | grep [s]leep
root      130188  0.0  0.0   7280   772 pts/1    S<   20:34   0:00 sleep 3000
root      130201  0.0  0.0   7280   836 pts/1    SN   20:34   0:00 sleep 3000
root      130303  0.0  0.0   7280   788 pts/1    SN   20:38   0:00 sleep 9000

案列四:模拟开启多线程

[root@instance-lpbn3wlc ~]# python aaa.py 
代码如下:
from threading import Thread
import time
import os

def task():
   time.sleep(100)

if __name__ == "__main__":
   print(os.getpid())
   for i in range(10):
       t=Thread(target=task)
t.start()

image-20201103210202809

查看进程树:以树状结构显示进程关系。

  • pstree UID:显示指定的进程及子进程。

  • -a:显示每个程序的完整指令,包含路径,参数或是常驻服务的标示。

[root@instance-lpbn3wlc ~]# yum install -y psmisc  最小化安装可能没有pstree,需要安装psmisc
[root@egon ~]# rpm -qf `which pstree`
psmisc-22.20-16.el7.x86_64
[root@oldboy ~]# pstree
systemd─┬─VGAuthService
       ├─auditd───{auditd}
       ├─chronyd
       ├─crond
       ├─dbus-daemon
       ├─irqbalance
       ├─login───bash
       ├─master─┬─pickup
       │        └─qmgr
       ├─ping
       ├─polkitd───6*[{polkitd}]
       ├─rsyslogd───2*[{rsyslogd}]
       ├─sshd───bash
       ├─sshd───bash───pstree
       ├─sshd
       ├─systemd-journal
       ├─systemd-logind
       ├─systemd-udevd
       ├─tuned───4*[{tuned}]
       └─vmtoolsd
[ rootaegon ~ ]# pstree 104239

查看ppid

image-20201103212341936

ps命令使用方法:

#对进程的CPU进行排序展示
[root@zls ~]# ps aux --sort %cpu |less

#对进程的占用物理内存排序
[root@zls ~]# ps aux --sort rss |less

#排序,是在记不住,那就自己排序
[root@zls ~]# ps aux|sort -k3 -n

#自定义显示字段
[root@zls ~]# ps axo user,pid,ppid,%mem,command |grep sshd
root        869      1  0.2 /usr/sbin/sshd -D
root       1194    869  0.2 sshd: root@pts/0
root       1307    869  0.2 sshd: root@pts/1
root       1574    869  0.2 sshd: root@pts/2

#显示进程的子进程
[root@zls ~]# yum install nginx -y
[root@zls ~]# systemctl start nginx
[root@zls ~]# ps auxf|grep [n]ginx
root       2033  0.0  0.1 125096  2112 ?        Ss   13:29   0:00 nginx: master process /usr/sbin/nginx
nginx      2034  0.0  0.1 125484  3148 ?        S    13:29   0:00  _ nginx: worker process

#查看指定进程PID
[root@zls ~]# ps aux|grep sshd
root       1157  0.0  0.1 105996  3604 ?        Ss   Feb27   0:00 /usr/sbin/sshd -D
[root@zls ~]# cat /run/sshd.pid
1157

#pgrep常用参数, -l -a
[root@zls ~]# pgrep sshd
869
1194
1307
1574
[root@zls ~]# pgrep -l sshd
869 sshd
1194 sshd
1307 sshd
1574 sshd
[root@zls ~]# pgrep -l -a sshd
869 /usr/sbin/sshd -D
1194 sshd: root@pts/0
1307 sshd: root@pts/1
1574 sshd: root@pts/2

#查看进程的pid
[root@oldboy ~]# pidof sshd
9209 5053 4851

pgrep命令

pgrep查看当前正在运行的进程,并列出与标准输出的选择标准相匹配的进程id。所有的标准都必须匹配。

  • -l:列出进程名称和进程ID。

  • -u:只匹配其有效用户ID已列出的进程。

# 列出指定进程的名称和ID
[chirou@duorou ~ ]$ pgrep -l bash
3088 bash
10218 bash

# 列出指定用户的进程
[chirou@duorou ~ ]$ pgrep -l -u chirou
3087 sshd
3088 bash
10217 sshd
10218 bash
10286 top

动态查看(top)

top命令的使用

[root@zls ~]# top    #动态查看进程状态

内部命令
s  # 修改刷新时间,单位是秒,可以是0.001s,建议不要设置很小,否则会过度消耗cpu
q  # 退出 或者ctrl+c
   
命令行选项
top -d 刷新时间s -p 进程pid  # 只看某一个进程的信息
top -d 刷新时间s -u 用户  # 只查看该用户开启的所有进程信息
   
[root@zls ~]# top -d 1 #1秒刷新一次
[root@zls ~]# top -d 1 -b -n 2 > top.txt
[root@oldboy ~]# # top -d 1 -p `pgrep egon | head -1`
[root@oldboy ~]# top -d 1 -p `pgrep sshd | head -1`,33 #查看sshd以及pid为33的进程
[root@oldboy ~]# top -d 1 -u egon #查看egon用户的进程
[root@oldboy ~]# top -b -n 2 > top.txt #将2次top信息写入到文件


top 常见指令
h   查看帮助(或者?)
l   关闭或开启第一部分第一行top信息的表示
z   高亮显示
1   数字1显示所有CPU的的信息
s   设置刷新时间
b   高亮现实处于R状态的进程
M   按内存使用百分比排序输出
P   按CPU使用百分比排序输出
R   对排序进行反转
f   增加自定义显示字段
k   kill掉指定PID进程
W   保存top环境设置 ~/.toprc
q   退出

#进程ID
PID
#用户
USER
#优先级,正常为20
PR  
#nice值,正常为0,负值表示高优先级,正值表示低优先级
NI    
#虚拟内存占用
VIRT
#真实内存占用
RES
#共享内存占用
SHR
#模式状态
S
#CPU占用百分比
%CPU
#内存占用百分比
%MEM
#运行时间
TIME+
#运行命令
COMMAND

排序

M 按照内存占用率从大到小排序
P 按照cpu占用率从大到小排序
N 按照PID从大到小排序
R 配合R代表倒序
hift + > # 移动排序字段
shift + < # 移动排序字段
按上下键查看所有进程

增加显示字段

  • 按 f 进入勾选你要显示的字段,上下键移动,按空格选中,按ESC或者q保存退出

image-20201104162520253

 

top前两行内容解析

top

#代表当前系统的时间
13:48:15

#代表运行了多长时间
up  1:59,  

#几个用户同时在线
4 users,  

#CPU平均负载:1分钟,5分钟,15分钟
load average: 0.00, 0.01, 0.05

#总共工作数量103个
Tasks: 103 total,  

#2个正在处理
2 running,  

#99个S状态
99 sleeping,  

#2个停止状态
2 stopped,  

#0个僵尸进程
0 zombie

top第三行内容解析

%Cpu(s): 
#用户态:用户占用CPU的百分比
0.0 us,  

#内核态:系统程序占用CPU的百分比(通常内核与硬件进行交互)
0.3 sy,  

dd </dev/zero >/dev/null bs=200M count=1000

#优先级:优先被调度的程序占用CPU百分比
0.0 ni,

#空闲:CPU空闲的百分比(windows也有)
99.7 id,  

#等待:CPU等待IO的完成时间
0.0 wa,  

#硬中断:占CPU的百分比
0.0 hi,
由与系统相连的外设(比如网卡、硬盘)自动产生的。主要是用来通知操作系统,系统外设状态的变化。比如当网卡收到数据包的时候,就会发出一个中断。我们通常所说的中断指的是硬中断(hardirq)

#软中断:占CPU的百分比
0.0 si,
为了满足实时系统的要求,中断处理应该是越快越好。linux为了实现这个特点,当中断发生的时候,硬中断处理那些短时间就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断(softirq)来完成。  

#虚拟机占用物理机的百分比
0.0 st

什么是中断?

中断是系统用来影响硬件设备请求的一种机制,它会打断进程的正常调度和执行,然后调用内核中的终端处理程序来影响设备的请求。


为什么要有中断?

CPU的处理速度远远快于外设的处理速度。如果CPU要和外设进行通信,CPU可以采用两种方式。

(1)轮训方式,但是这种方式会让CPU的资源无法得到更好地利用,CPU只会干一件事情,也会做很多的无用功(在网上看到一个比较有意思的比喻,比如你在厨房烧开水的时候,采用轮训的方式就好比一直盯着这个水壶,直到它烧开为止,中间会浪费很多的时间)。

(2)中断方式,CPU可以在外设没有准备就绪的时候,可以干别的任务(处理进程,处理中断)。一旦外设准备就绪,外设会给CPU发送一个中断信号,CPU处理完毕,接着执行之前被打断的任务,保证了CPU的资源得到更好的利用。(比如在厨房烧开水的时候,别人来敲门了,你可以去开门,或者去看会电视,等到水壶发出水烧开的声音的时候,再回头去处理它)


那么中断会带来什么问题?

由于中断处理程序会打断其他进程的运行,所以,为了减少对正常进程运行调度的影响,中弄断处理程序就需要尽可能快的运行,如果中弄断本身要做的事情不多,那么处理起来也不会有太大的问题,但是如果中断要处理的事情很多,中断服务程序就有可能要运行很长时间。

特别是,中断处理程序在影响中断时,还会临时关闭中断,这就会导致上一次中断处理完成之前,其他中断都能不能响应,也就是说中断有可能会丢失。

以外卖为例:加入你定了2份外卖

一份主食和一份饮料,由2个不同的配送员来配送。这次你不用时时等待着,两份外卖都约定了电话取外卖的方式。那么问题又来了。

当第一份外卖送到时,配送员给你打了个很长的电话,商量发票处理的方式,与此同时,第二个配送员也到了,也想给你打电话,但是会占线,因为电话占线(也就关闭了中断的响应),第二个配送给你打电话打不通,所以,那么很有可能在尝试几次还占线,就走了(丢失了一次中断)


系统的软中断

针对上述的中断所带来的影响,如果对于系统来说,每次都真的只能处理一次中断,那真的会导致大量中断丢失,从而导致用户的请求无法响应

事实上,为了解决中断处理程序执行过长的和丢失中断的问题,Linux将中断处理过程分成了两个阶段: 第一阶段:用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关工作 第二阶段:用来延迟处理第一阶段未完成的工作,通常以内核线程的方式运行。

你猜的没错,还是外卖的那个例子:

第一阶段:当你接到第一个配送员电话时,你可以跟他说,你已经知道了,其他事见面再细说,然后就可以挂断电话了。

第二阶段:才是取外卖,然后见面聊发票的处理动作。

如此一来,第一个配送员不会在电话里占用你很长时间,第二个配送员来的时候,照样可以打通电话。


生产例子

当网卡在接收数据包的时候,会通过硬中断的方式通知内核,有新数据到了。这时,内核就应该调用中断处理程序来影响它。对第一阶段来说,既然是快速处理,其实就是把网卡接收到的数据包,先放置内存当中,然后更新一下硬件寄存器的状态(表示数据已经读好了),而第二阶段,被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它发送给应用程序。

言简意赅:

第一阶段:直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行。 第二阶段:由内核触发该请求,也就是我们常说的软中断,特点是延迟执行。

Linux软中断与硬中断小结:

1.Linux中弄断处理程序分为上半部和下半部:

  • 上半部对应硬中断,用来快速处理

  • 下半部对应软中断,用来异步处理上半部未完成的工作

2.Linux中的软中断包括:网络收发,定时,调度等各种类型,可以通过/proc/softirqs来观察中断的运行情况

在企业中,会经常听说一个问题,就是大量的网络小包会导致性能问题,为啥呢?

因为大量的网络小包会导致频繁的硬中断和软中断,所以大量的网络小包传输速度很慢,但如果将所有的网络小包"打包","压缩"一次性传输,是不是会快很多。

就好比,你在某东自营买了100个快递,都是第二天到,如果分100个快递员,给你配送,你一天要接100个电话,老得劲了奥~~~~ 但是如果,某东只让一个快递员,把你买的100个快递,打包成一个大包裹,派送给你,会不会快很多?小老弟

 

系统平均负载

每次发现系统变慢时,我们通常做的第一件事,就是执行top或者uptime命令,来了解系统的负载情况。

[root@oldboy ~]#  uptime
19:49:21 up 3 days,  1:33,  2 users,  load average: 0.07, 0.26, 1.85
#后面三个数依次是:过去1分钟,5分钟,15分钟的平均负载(Load Average)

 

什么是平均负载?

平均负载是指,单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数

PS:平均负载与CPU使用率并没有直接关系。

可运行状态和不可中断状态是什么?

1.可运行状态进程,是指正在使用CPU或者正在等待CPU的进程,也就是我们用PS命令看的处于R状态的进程

2.不可中断进程,(你在做什么事情的时候是不能被打断的呢?...不可描述)系统中最常见的是等待硬件设备的IO相应,也就是我们PS命令中看到的D状态(也成为Disk Sleep)的进程。

例如:当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,他是不能被其他进程或者中断程序打断的,这个是后续的进程就处于不可中断的状态,如果此时进程强制被打断,kill -9 ... perfect准备好护照吧,有多远,走多远,千万别回来了。不可中断状态实际上是系统对进程和硬件设备的一种保护机制

因此,可以简单理解为,平均负载其实就是单位时间内的活跃进程数。

  • 平均负载多少时合理?

    最理想的状态是每个CPU上都刚还运行着一个进程,这样每个CPU都得到了充分利用。所以在评判负载时,首先你要知道系统有几个CPU,这可以通过top命令获取,或grep 'model name' /proc/cpuinfo

    例1: 架设现在在4,2,1核的CPU上,如果平均负载为2时,意味着什么呢? 1.在4个CPU的系统上,意味着CPU有50%空闲。 2.在2个CPU的系统上,以为这所有的CPU都刚好完全被占用。 3.在1个CPU的系统上,则意味着有一半的进程竞争不到CPU。

    那么...平均负载有三个数值,我们应该关注哪个呢?

    实际上,我们都需要关注,就好比北京5月份的天气,如果只看晚上天气,感觉在过冬天,但是你结合了早上,中午,晚上三个时间点的温度来看,基本就可以全方位的了解这一天的天气情况了。

    1.如果1分钟,5分钟,15分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。 2.如果1分钟的值远小于15分钟的值,就说明系统像最近1分钟的负载在减少,而过去15分钟内却有很大的负载。 3.反过来,如果1分钟的大于15分钟,就说明最近1分钟的负载在增加,这种增加有可能只是临时的,也有可能还会持续上升...说的跟股票似的。所以要持续观察。(emmmm...一旦K线下降,就拋,割肉) 4.一旦1分钟的平均负载接近或超过了CPU的个数,就意味着,系统正在发生过载的问题,这时候就得分析问题了,并且要想办法优化。

    架设我们在有2个CPU系统上看到平均负载为2.73,6.90,12.98那么说明在过去1分钟内,系统有136%的超载(2.73/2100%=136%) 5分钟:(6.90/2100%=345%) 15分钟:(12.98/2*100%=649%) 但整体趋势来看,系统负载是在逐步降低。


  • 企业中平均负载多高需要重点关注呢?

    当平均负载高于CPU数量70%的时候,你就应该分析排查负载高的问题了,一旦负载过高,就可能导致进程相应变慢,进而影响服务的正常功能。 但70%这个数字并不是绝对的,最推荐的方法,还是把系统的平均负载监控起来,然后根据更多的历史数据,判断负载的变化趋势,当发现负载有明显升高的趋势时,比如说负载翻倍了,你再去做分析和调查。


  • 平均负载与CPU的使用率有什么关系

    在十几工作中,我们经常容易把平均负载和CPU使用率混淆,所以在这里,我也做一个区分,可能你会感觉到疑惑,既然平均负载代表的是活跃进程数,那平均负载搞了,不就意味着CPU使用率高嘛?

    我们还是要回到平均负载的含义上来,平均负载指的是每单位时间内,处于可运行状态和不可中断状态的进程数,所以,它不仅包括了正在使用CPU的进程数,还包括等待CPU和等待IO的进程数。

    而CPU的使用率是单位时间内,CPU繁忙情况的统计,跟平均浮现在并不一定完全对应。 比如:

    CPU密集型进程,使用大量的CPU会导致平均负载升高,此时这两者是一致的。 IO密集型进程,等待IO也会导致平均负载升高,但CPU使用率不一定很高。

    大量等待CPU的进程调度也会导致平均负载升高,此时的CPU使用率也会比较高。

    但是CPU的种类也分两种:

    • CPU密集型

    • IO密集型

     

     

    例如MySQL服务器,就需要尽量选择使用IO密集型CPU

  • 平均负载案例分析实战

    下面我们以三个示例分别来看这三中情况,并用:stress、mpstat、pidstat等工具找出平均负载升高的根源

    stress是Linux系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。

    mpstat是多核CPU性能分析工具,用来实时检查每个CPU的性能指标,以及所有CPU的平均指标。

    pidstat是一个常用的进程性能分析工具,用来实时查看进程的CPU,内存,IO,以及上下文切换等性能指标。

#安装stress命令
[root@zls ~]# yum install -y stress

案例一:CPU密集型

我们在第一个中断运行stress命令,模拟一个CPU使用率100%的场景:

#第一个终端执行
[egon@oldboy ~]$ stress --cpu 1 --timeout 600


#第二个终端查看
[egon@oldboy ~]$ uptime
16:02:08 up 3 days, 21:46,  2 users,  load average: 0.69, 0.25, 0.13


#高亮显示变化区域
[egon@oldboy ~]$ watch -d uptime
Every 2.0s: uptime                                                                                                                                                                                                                                      Sun Jul 14 22:05:16 2019

22:05:16 up 10:16,  4 users,  load average: 2.84, 1.05, 0.41

使用mpstat查看CPU使用率的变化情况

[root@oldboy ~]# mpstat -P ALL 5

Linux 4.18.0-193.6.3.el8_2.x86_64 (oldboy)      11/05/2020     _x86_64_       (2 CPU)

03:55:56 PM CPU   %usr   %nice   %sys %iowait   %irq   %soft %steal %guest %gnice   %idle
03:56:01 PM all    1.10    0.00    0.40    0.00    0.00    0.10    0.00    0.00    0.00   98.40
03:56:01 PM    0    0.80    0.00    0.20    0.00    0.00    0.20    0.00    0.00    0.00   98.80
03:56:01 PM    1    1.41    0.00    0.60    0.00    0.00    0.00    0.00    0.00    0.00   97.99

03:56:01 PM CPU   %usr   %nice   %sys %iowait   %irq   %soft %steal %guest %gnice   %idle
03:56:06 PM all    0.70    0.00    0.50    0.10    0.20    0.10    0.00    0.00    0.00   98.40
03:56:06 PM    0    0.60    0.00    0.20    0.00    0.20    0.00    0.00    0.00    0.00   99.00
03:56:06 PM    1    0.80    0.00    0.80    0.20    0.20    0.20    0.00    0.00    0.00   97.80

从终端2可以看到,1分钟平均负载会慢慢增加到2.00,而从终端三中还可以看到,正好有一个CPU的使用率为100%,但他的IOwait只有0,这说明平均负载的升高正式由于CPU使用率为100%,那么到底哪个进程导致CPU使用率为100%呢?可以使用pidstat来查询

#间隔5秒输出一组数据
[root@oldboy ~]# pidstat -u 5 1
Linux 4.18.0-193.6.3.el8_2.x86_64 (oldboy)      11/05/2020     _x86_64_       (2 CPU)

03:53:54 PM   UID       PID   %usr %system %guest   %wait   %CPU   CPU Command
03:53:59 PM     0       567    0.00    0.20    0.00    0.00    0.20     1 systemd-journal
03:53:59 PM     0    352069    0.80    0.40    0.00    0.00    1.20     1 hosteye

Average:     UID       PID   %usr %system %guest   %wait   %CPU   CPU Command
Average:        0       567    0.00    0.20    0.00    0.00    0.20     - systemd-journal
Average:        0    352069    0.80    0.40    0.00    0.00    1.20     - hosteye

案例二:I/O密集型

还是使用stress命令,但是这次模拟IO的压力

[root@oldboy ~]# stress --io 1 --timeout 600s

在第二个终端运行uptime查看平均负载的变化情况

[egon@oldboy ~]$ watch -d uptime

Every 2.0s: uptime                                                                                                                                                                                                                                     Sun Jul 14 22:17:38 2019

22:17:38 up 10:28,  4 users, load average: 2.47, 2.25, 1.61

在第三个终端运行mpstat查看CPU使用率的变化情况

[egon@oldboy ~]$ mpstat -P ALL 5
Linux 3.10.0-862.el7.x86_64 (zls)   2019年07月14日     _x86_64_   (1 CPU)

22时19分32秒 CPU   %usr   %nice   %sys %iowait   %irq   %soft %steal %guest %gnice   %idle
22时19分37秒 all    2.78    0.00   97.22    0.00    0.00    0.00    0.00    0.00    0.00    0.00
22时19分37秒    0    2.78    0.00   97.22    0.00    0.00    0.00    0.00    0.00    0.00    0.00

22时19分37秒 CPU   %usr   %nice   %sys %iowait   %irq   %soft %steal %guest %gnice   %idle
22时19分42秒 all    3.01    0.00   96.99    0.00    0.00    0.00    0.00    0.00    0.00    0.00
22时19分42秒    0    3.01    0.00   96.99    0.00    0.00    0.00    0.00    0.00    0.00    0.00

#发现CPU与内核打交道的sys占用非常高

那么到底哪个进程导致iowait这么高呢?

[root@zls ~]# pidstat -u 5 1
Linux 3.10.0-862.el7.x86_64 (zls)   2019年07月14日     _x86_64_   (1 CPU)

22时20分59秒   UID       PID   %usr %system %guest   %CPU   CPU Command
22时21分04秒     0      6900    0.00    0.20    0.00    0.20     0 kworker/0:0
22时21分04秒     0     10104    2.76   83.07    0.00   85.83     0 stress
22时21分04秒     0     10105    0.00   10.63    0.00   10.63     0 kworker/u256:2


平均时间:   UID       PID   %usr %system %guest   %CPU   CPU Command
平均时间:     0      6900    0.00    0.20    0.00    0.20     - kworker/0:0
平均时间:     0     10104    2.76   83.07    0.00   85.83     - stress
平均时间:     0     10105    0.00   10.63    0.00   10.63     - kworker/u256:2

这时候发现看到的数据比较少,需要更新一下命令:

#下载新版本的包
[root@zls ~]# wget http://pagesperso-orange.fr/sebastien.godard/sysstat-11.7.3-1.x86_64.rpm

#升级到新版本
[root@zls ~]# rpm -Uvh sysstat-11.7.3-1.x86_64.rpm
准备中...                          ################################# [100%]
正在升级/安装...
  1:sysstat-11.7.3-1                 ################################# [ 50%]
正在清理/删除...
  2:sysstat-10.1.5-17.el7            ################################# [100%]

然后再次查看结果,明显显示的数据多了

[egon@oldboy ~]$ pidstat -u 5 1

Linux 3.10.0-862.el7.x86_64 (zls)   2019年07月14日     _x86_64_   (1 CPU)

22时24分40秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
22时24分45秒     0       281    0.00    0.20    0.00    0.40    0.20     0  xfsaild/sda3
22时24分45秒     0     10104    2.99   82.67    0.00    0.00   85.66     0  stress
22时24分45秒     0     10105    0.00    8.76    0.00   92.43    8.76     0  kworker/u256:2
22时24分45秒     0     10118    0.20    0.40    0.00    0.00    0.60     0  watch
22时24分45秒     0     10439    0.00    3.98    0.00   94.82    3.98     0  kworker/u256:3
22时24分45秒     0     11007    0.00    0.20    0.00    0.00    0.20     0  pidstat

平均时间:   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
平均时间:     0       281    0.00    0.20    0.00    0.40    0.20     -  xfsaild/sda3
平均时间:     0     10104    2.99   82.67    0.00    0.00   85.66     -  stress
平均时间:     0     10105    0.00    8.76    0.00   92.43    8.76     -  kworker/u256:2
平均时间:     0     10118    0.20    0.40    0.00    0.00    0.60     -  watch
平均时间:     0     10439    0.00    3.98    0.00   94.82    3.98     -  kworker/u256:3
平均时间:     0     11007    0.00    0.20    0.00    0.00    0.20     -  pidstat

案例三:大量进程的场景

当系统运行进程超出CPU运行能力时,就会出现等待CPU的进程。

1.首先,我们还是使用stress命令,模拟的是多个进程

[root@zls ~]# stress -c 4 --timeout 600

2.由于系统只有一个CPU,明显比4个进程要少的多。因此,系统的CPU处于严重过载状态

[root@oldboy ~]# uptime
Every 2.0s: uptime                                                                                                                                                                                                                                      Sun Jul 14 22:28:50 2020

22:28:50 up 10:39,  4 users,  load average: 3.96, 3.89, 3.00

3.在运行pidstat命令来查看一下进程的情况

[root@zls ~]# pidstat -u 5 1
Linux 3.10.0-862.el7.x86_64 (zls)   2019年07月14日     _x86_64_   (1 CPU)

22时31分12秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
22时31分17秒     0     11317   24.75    0.00    0.00   75.05   24.75     0  stress
22时31分17秒     0     11318   24.95    0.00    0.00   75.45   24.95     0  stress
22时31分17秒     0     11319   24.75    0.00    0.00   75.25   24.75     0  stress
22时31分17秒     0     11320   24.75    0.00    0.00   75.45   24.75     0  stress
22时31分17秒     0     11381    0.20    0.40    0.00    0.00    0.60     0  watch
22时31分17秒     0     11665    0.00    0.20    0.00    0.00    0.20     0  pidstat

平均时间:   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
平均时间:     0     11317   24.75    0.00    0.00   75.05   24.75     -  stress
平均时间:     0     11318   24.95    0.00    0.00   75.45   24.95     -  stress
平均时间:     0     11319   24.75    0.00    0.00   75.25   24.75     -  stress
平均时间:     0     11320   24.75    0.00    0.00   75.45   24.75     -  stress
平均时间:     0     11381    0.20    0.40    0.00    0.00    0.60     -  watch
平均时间:     0     11665    0.00    0.20    0.00    0.00    0.20     -  pidstat

总结:

1.平均负载高有可能是CPU密集型进程导致的 2.平均负载高并不一定代表CPU的使用率就一定高,还有可能是I/O繁忙 3.当发现负载高时,可以使用mpstat、pidstat等工具,快速定位到,负载高的原因,从而做出处理

 

企业案例,Linux假死是怎么回事

什么是假死?

所谓假死,就是能ping通,但是ssh不上去;任何其他操作也都没反应,包括上面部署的nginx也打不开页面。


假死其实很难出现一次

作为一个多任务操作系统,要把系统忙死,忙到ssh都连不上去,也不是那么容易的。尤其是现在还有fd保护、进程数保护、最大内存保护之类的机制。 你可以fork很多进程,系统会变得很慢,但是ssh还是能连上去;你可以分配很多内存,但是内存多到一定程度oom killer就会把你的进程杀掉,于是ssh又能工作了。


假死如何实现

有一个确定可以把系统搞成假死的办法是:主进程分配固定内存,然后不停的fork,并且在子进程里面sleep(100)。 也就是说,当主进程不停fork的时候,很快会把系统的物理内存用完,当物理内存不足时候,系统会开始使用swap;那么当swap不足时会触发oom killer进程; 当oom killer杀掉了子进程,主进程会立刻fork新的子进程,并再次导致内存用完,再次触发oom killer进程,于是进入死循环。而且oom killer是系统底层优先级很高的内核线程,也在参与死循环。


系统假死为何能ping同无法连接

此时机器可以ping通,但是无法ssh上去。这是由于ping是在系统底层处理的,没有参与进程调度;sshd要参与进程调度,但是优先级没oom killer高,总得不到调度。


出现假死怎么办

为什么要费那么大的力气把机器搞死?我们知道假死是怎么产生的即可,这样可以针对假死的原因进行预防。 (其实假死的情况很少发生,只有当代码写的bug很多的情况下会出现。) 其实建议使用nice将sshd的进程优先级调高。这样当系统内存吃紧,还能勉强登陆sshd,进入调试。然后分析故障。

 

进程的优先级设置

什么是优先级?

  • 优先级指的是优先享受资源。


那么在系统中如何给进程配置优先级

在启动进程时,为不同的进程使用不同的调度策略。

nice值越高:表示优先级越低,例如19,该进程容易将CPU使用量让给其他进程。 nice值越低:表示优先级越高,例如-20,该进程更不倾向于让出CPU。

1)使用top命令查看进程的优先级

#使用top看优先级
[root@oldboy ~]# top

2)使用nice命令指定进程优先级

#打开一个终端
[root@oldboy ~]# nice -n -5 vim a.txt

#打开另一个终端,查看进程的优先级
[root@oldboy ~]# ps aux|grep [v]im
root      579435  0.1  0.2  48360  8344 pts/0    S<+  16:24   0:00 vim a.txt
[root@oldboy ~]# ps axo command,nice|grep [v]im
vim a.txt                    -5

3)ps -l 命令

其中几个重要的信息有:

  • UID:代表执行者身份

  • PID:代表这个进程的代号

  • PPID:代表这个进程是由那个进程发展衍生而来的,

  • PRI:代表这个进程可被执行的优先级,其值越小越早被执行

  • NI:代表这个进程的nice值

    PRI 即进程的优先级, 此值越小进程的优先级别越高。而NI , 也就是我们所要说的nice值( 通过nice命令设置), 其表示进程可被执行的优先级的修正数值。如前面所说, PRI 值越小越快被执行, 那么加入nice值后, 将会使得PRI 变为: PRI ( new )=PRI ( old )+nice。

    所以, nice命令设置的优先级不是程序最终的优先级, 而只是优先级的修正数值。

    renice命令允许用户修改一个正在运行的进程的优先权。

    也可以对已运行的进程设置新的优先级

    [root@oldboy ~]# renice -20 578703

给进程发送信号

信号管理进程

当程序运行为进程后,如果希望强行停止就可以使用kill命令对进程发送关闭信号,除了kill还有pkill、killall

定义守护进程的角色 结束用户会话和进程 kill,killall,pgrep,pkill

image-20201104204118975

[root@oldboy ~]#  kill -l //列出所有支持的信号

//常见信号列表:
数字信号    信号别名        作用
1     HUP     挂起信号,往往可以让进程重新配置
2       INT     中断信号,起到结束进程的作用,和ctrl + c 的作用一样
3     QUIT        让进程退出,结果是进程退出
9     KILL        直接结束进程,不能被进程捕获
15     TERM        进程终止,这是默认信号
18     CONT        被暂停的进程将继续恢复运行
19     STOP        暂停进程
20     TSTP        用户停止请求,作用类似于ctrl + z 把进程放到后台并暂停

实例1:kill-1重新加载配置文件

setenforce 0
systemctl stop firwalld   #保证网络畅通

# 1、启动vsftpd服务
systemctl start vsftpd # 默认匿名用户共享根目录为/var/ftp
[ rootaegon ~ ]# ls /var/ftp/
centos7 pub
# 2、打开浏览器, 输入ftp://192.168.12.42/҅, 看到的是/var/ftp下的内容

# 3、修改vsftp的配置文件, 默认匿名用户共享根目录改为/test
[root@egon ~]# sed -i '$a anon_root=/test' /etc/vsftpd/vsftpd.conf

# 4、在不启动服务vsftpd的情况下让其加载配置文件
[root@egon ~]# ps aux |grep [v]sftpd
root 50695 0.0 0.0 53288 780 ? Ss 11์01 0:00
/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

[root@egon ~]# kill -1 50695 # 这期间vsftpd的pid是始终不变的, 因为从未关闭过进程
[root@egon ~]# ps aux |grep [v]sftpd
root 50695 0.0 0.0 53288 780 ? Ss 11月01 0:00
/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

#5、打开浏览器, 重新输入ftp://192.168.12.42/, 看到的是/test下的内容

// vsftpd 进程发送信号 1,15
[root@zls ~]# systemctl start vsftpd
//发送重启信号,例如 vsftpd 的配置文件发生改变,希望重新加载
[root@zls ~]# kill -1 9160
//发送停止信号,vsftpd 服务有停止的脚本 systemctl stop vsftpd
[root@zls ~]# kill 9160


// 给vim进程发送信号 9,15
[root@zls ~]# touch file1 file2
//使用远程终端1打开file1
[root@zls ~]# tty
/dev/pts/1
[root@zls ~]# vim file1
//使用远程终端2打开file2
[root@zls ~]# tty
/dev/pts/2
[root@zls ~]# vim file2
//查看当前进程pid
[root@zls ~]# ps aux |grep vim
root 4362 0.0 0.2 11104 2888 pts/1 S+ 23:02 0:00 vim file1
root 4363 0.1 0.2 11068 2948 pts/2 S+ 23:02 0:00 vim file2
//发送15信号
[root@zls ~]# kill 4362
//发送9信号
[root@zls ~]# kill -9 4363
//还可以同时给所有vim进程发送信号, 模糊匹配,同时给多个进程发送信号
[root@oldboy ~]# killall vim


//使用pkill踢出从远程登录到本机的用户, pkill  类似killall
[root@oldboy ~]# w
18:36:24 up 4 days, 20 min,  2 users,  load average: 0.00, 0.02, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
egon     pts/0    139.226.12.198   15:50    1:18   0.28s  0.03s -bash
egon     pts/1    139.226.12.198   10:35    0.00s  0.24s  0.04s sshd: egon [priv]

//终止 pts/0上所有进程, 除了bash本身
[root@oldboy ~]# pkill -t pts/0
//终止pts/0上所有进程, 并且bash也结束(用户被强制退出)
[root@oldboy ~]# pkill -9 -t pts/0

//列出egon用户的所有进程,-l输出pid
[root@oldboy ~]# pgrep -l -u egon
561459 systemd
561462 (sd-pam)
564625 sshd
564626 bash
577861 sshd
577862 bash
586131 bash
586153 bash
586287 vim

实例2:kill杀死进程

# kill -15 不加-15 ,默认发出的就是-15的信号
[root@oldboy ~]# systemctl start vsftpd
[root@oldboy ~]# ps aux |grep [v]sftpd
root      340754  0.0  0.0  27016  1204 ?        Ss   Nov04   0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
[root@oldboy ~]# kill 340754

# kill -9 强制杀死
[root@oldboy ~]# systemctl start nginx
[root@oldboy ~]# ps -aux | grep nginx
root      582607  0.0  0.0 117748  2176 ?        Ss   17:25   0:00 nginx: master process /usr/sbin/nginx
nginx     582608  0.0  0.2 149260  8308 ?        S    17:25   0:00 nginx: worker process
nginx     582609  0.0  0.2 149260  8308 ?        S    17:25   0:00 nginx: worker process
root      582695  0.0  0.0  12108   980 pts/0    S+   17:26   0:00 grep --color=auto nginx
[root@oldboy ~]# kill -9 582608

关于HUP信号

要了解Linux的HUP信号,需要从hangup说起

在unxi的早期版本中,每个终端都会通过modem和系统通讯

当 modem 断开连接时, 就会给终端发送 hangup 信号来通知其关闭所有子进程。

综上, 我们知道, 当用户注销 (Iogout) 或者网络断开或者终端关闭(注意注意注意, 一定是终端整体关闭, 不是单纯的exit), 终端都会收到Linux HUP信号 (hangup) 信号, 然后终端在结束前会关闭其所有子进程。

**

如果我们想让我们的进程在后台一直运行, 不要因为用户注销 (Iogout) 或者网络断开或者终端关闭而一起被干掉, 那么我们有两种解决方案

  • 方案1 : 让进程忽略Linux HUP信号

  • 方案2: 让进程运行在新的会话里, 从而成为不属于此终端的子进程, 就不会在当前终端挂掉的情况下一起被带走。

nohup命令

针对方案1 , 我们可以使用nohup命令, nohup 的用途就是让提交的命令忽略 hangup 信号, 该命令通常与&符号一起使用。

nohup 的使用是十分方便的, 只需在要处理的命令前加上 nohup 即可, 但是 nohup 命令会从终端解除进程的关联, 进程会丢掉smD0Um , smDERR 的链接。标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般我们可在结尾加上" s" 来将命令同时放入后台运行, 也可用" >filename 2>s 1 " 来更改缺省的重定向文件名。

示例

# 在终端一运行
[root@oldboy ~]# nohup ping www.baidu.com &
[1] 596211
[root@oldboy ~]# nohup: ignoring input and appending output to 'nohup.out'

# 在终端二查看到进程ping的信息,它的父进程为594938
[root@oldboy ~]# ps -elf |grep [p]ing
4 S root      596211  594938  0  80   0 - 13796 x64_sy 22:05 pts/1    00:00:00 ping www.baidu.com

# 关闭终端一窗口,然后再去终端二查看ping进程是否被一起带走
[root@oldboy ~]# ps -elf |grep [p]ing
4 S root      596211       1  0  80   0 - 13796 -      22:05 ?        00:00:00 ping www.baidu.com
#以上看出ping的进程依然在运行,它的父进程pid变成了1,即init 进程

setsid命令

针对方案1 , 我们还可以用setsid命令实现, 原理与3.1 是一样的, setid是直接将进程的父pid设置成1 , 即让运行的进程归属于init的子进程, 那么除非init结束, 该子进程才会结束, 当前进程所在的终端结束后并不会影响进程的运行。

# 1、在终端1中执行命令
[root@oldboy ~]# sedsid www.bai.com &
[1] 596377

 #2、关闭终端1窗口

# 3、在终端2中查看
[root@oldboy ~]# ps -elf |grep [p]ing
4 S root      596211       1  0  80   0 - 13796 x64_sy 22:05 ?        00:00:00 ping www.baidu.com

在子sheII中提交任务

# 1、在终端1中执行命令
[root@oldboy ~]#  (ping www.baidu.com &) # 提交的作业并不在作业列表中

# 2、关闭终端1窗口

# 3、在终端2中查看
[root@oldboy ~]# ps -elf |grep [p]ing
4 S root      596890       1  0  80   0 - 13796 x64_sy 22:45 pts/2    00:00:00 ping www.baidu.com


可以看到新提交的进程的父ID(PPID  ) 为1(init进程的 PID  ) , 并不是当前终端的进程 ID 。因此并不属于当前终端的子进程, 从而也就不会受到当前终端的工inux HUP 信号的影响了。
screen命令

 

直接关闭xshell窗口

# 1、在终端1中执行命令
[root@oldboy ~]# ping www.baidu.com &>/dev/null

#2、在终端2中查看
[root@oldboy ~]# ps -elf |grep [p]ing
4 S root      596501  596468  0  80   0 - 13796 x64_sy 22:25 pts/0    00:00:00 ping www.baidu.co
#3、关闭终端1窗口
# 4、在终端2中查看,所有在窗口一执行的进程都被带走
[root@oldboy ~]# ps -elf |grep [p]ing

用 logout或exit 注销用户

# 1、在终端1中执行命令
[root@oldboy ~]# ping www.baidu.com &>/dev/null &
[1] 596677

#2、在终端2中查看
[root@oldboy ~]# ps -elf |grep [p]ing
4 S root      596677  596629  0  80   0 - 13796 x64_sy 22:37 pts/0    00:00:00 ping www.baidu.com

#3、用 logout或exit 注销用户
[root@oldboy ~]# exit

# 4、在终端2中查看
[root@oldboy ~]# ps -elf |grep [p]ing
4 S root      596677       1  0  80   0 - 13796 x64_sy 22:37 pts/0    00:00:00 ping www.baidu.com

screen 命令

#安装screen命令
[root@zls ~]# yum install -y screen

# 1、在终端1中执行命令
[root@oldboy ~]# screen vim 1.txt


#2、在终端2中查看
[root@oldboy ~]# ps -elf |grep [v]im
4 S root      597097  596353  0  80   0 -  9340 -      22:59 pts/1    00:00:00 screen vim 1.txt
5 S root      597098  597097  0  80   0 - 10938 core_s 22:59 ?        00:00:00 SCREEN vim 1.txt
4 S root      597099  597098  0  80   0 - 12080 core_s 22:59 pts/2    00:00:00 vim 1.txt

#3、关闭终端一窗口

# 4、在终端2中查看
[root@oldboy ~]# ps -elf |grep [v]im
5 S root      597098       1  0  80   0 - 10938 core_s 22:59 ?        00:00:00 SCREEN vim 1.txt
4 S root      597099  597098  0  80   0 - 12080 core_s 22:59 pts/2    00:00:00 vim 1.txt

ps:原理分析
screen程序会帮我们管理运行的命令, 退出screen, 我们的命令还会继续运行, 若关闭screen所在的终端, 则screen程序的ppid变为1 , 所以screen不会死掉, 对应着它帮我们管理的命令也不会退出

# 4: 重新连接会话在终端1中运行
[root@oldboy egon]# scree-ls

[root@oldboy egon]# n=1;while true;do echo $n;sleep 1;((n++));done
[ rootaegon ~ ]# 按下ctrl+a , 然后再按下ctrl+d , 注意要连贯, 手别哆嗦,

[ rootaegon ~ ]# 此时可以关闭整个终端, 我们的程序并不会结束

打开一个新的终端
[root@oldboy ~]# screen -ls
There are screens on:
597258.pts-1.oldboy (Detached)
567588.egon_AV (Detached)
2 Sockets in /run/screen/S-root.

[root@oldboy ~]# screen -r 597258 #会继续运行

远程演示

# 在终端1:
[root@egon ~]# screen -S egon_av

# 开启一个新的终端, 在该终端执行的命令, 终端1会同步显示
[root@egon ~]# screen -x egon_av

proc 文件系统

 

 

查看网络状态

netstat

[root@oldboy egon]# netstat -tnlp  # 查看正在监听的, 且使用tcp协议的进程
-t	tcp协议
-u	udp协议
-l	listen
-p	PID/ Program name
-n	不反解, 不将IP地址解析为主机名, 不将端口号解析成协议名 ( 80 ---> http)

实例
[root@oldboy ~]# netstat -an | grep :22
[root@oldboy ~]# netstat -an | grep :80
[root@oldboy ~]# lsof -i:22

[root@localhost ~]# route -n   #查看网关
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.146.2   0.0.0.0         UG    0      0        0 ens33
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 ens33
192.168.146.0   0.0.0.0         255.255.255.0   U     0      0        0 ens33

proc文件系统

硬盘

[root@localhost ~]# du -sh /etc   统计文件夹的大小
30M /etc
[root@localhost ~]# df   #显示磁盘空间统计信息
文件系统         1K-块   已用     可用 已用% 挂载点
/dev/sda3      18520064 1013052 17507012    6% /
devtmpfs         973152       0   973152    0% /dev
tmpfs            982980       0   982980    0% /dev/shm
tmpfs            982980    8752   974228    1% /run
tmpfs            982980       0   982980    0% /sys/fs/cgroup
/dev/sda1        484004  113248   370756   24% /boot
tmpfs            196596       0   196596    0% /run/user/0
[root@localhost ~]# df -H #显示磁盘容量单位
文件系统       容量 已用 可用 已用% 挂载点
/dev/sda3       19G  1.1G   18G    6% /
devtmpfs       997M     0 997M    0% /dev
tmpfs           1.1G     0  1.1G    0% /dev/shm
tmpfs           1.1G  9.0M 998M    1% /run
tmpfs           1.1G     0  1.1G    0% /sys/fs/cgroup
/dev/sda1       496M 116M 380M   24% /boot
tmpfs           202M     0 202M    0% /run/user/0
[root@localhost ~]# df -T #显示文件系统格式
文件系统       类型       1K-块   已用     可用 已用% 挂载点
/dev/sda3     xfs      18520064 1013052 17507012    6% /
devtmpfs       devtmpfs   973152       0   973152    0% /dev
tmpfs         tmpfs      982980       0   982980    0% /dev/shm
tmpfs         tmpfs      982980    8752   974228    1% /run
tmpfs         tmpfs      982980       0   982980    0% /sys/fs/cgroup
/dev/sda1     xfs        484004  113248   370756   24% /boot
tmpfs         tmpfs      196596       0   196596    0% /run/user/0

CPU:/proc/cpuinfo

[root@localhost ~]# grep "processor" /proc/cpuinfo #逻辑CPU个数
processor : 0
processor : 1
[root@localhost ~]# grep "physical id" /proc/cpuinfo #物理CPU个数
physical id : 0
physical id : 2
[root@localhost ~]# grep "cpu cores" /proc/cpuinfo   #CPU核数
cpu cores : 1
cpu cores : 1
[root@localhost ~]# grep "processor" /proc/cpuinfo |wc -l
2

[root@localhost ~]# cat /proc/cpuinfo #查看系统中CPU的提供商和相关配置信息
[root@localhost ~]# lscpu #浏览CPU信息
[root@localhost ~]# egrep --color 'lm|vmx|svm' /proc/cpuinfo

内存:/proc/meminfo

# 查看内存
[root@localhost ~]# less /proc/meminfo
[root@localhost ~]# free -m  #以M为单位显示
              total        used        free      shared  buff/cache   available
Mem:           1919          92        1687           8         140        1667
Swap:          1906           0        1906

[root@localhost ~]# free -wm
              total        used        free      shared     buffers       cache   available
Mem:           1919          92        1687           8           2         138        1667
Swap:          1906           0        1906

# 需要注意的是
free表示的是当前完全没有被程序使用的内存;
而cache在有需要时, 是可以被释放出来以供其它进程使用的 (当然, 并不是所有cache都可以释放, 比如当前被用作ramfs的内存) 。

# 而available才是真正表明系统目前可以提供给新启动的应用程序使用的内存。
/proc/meminfo从3 .14内核版本开始提供MemAvailable的值; 在2 .6 .27~ 3 .14版本之间, 是free程
序自己计算available的值; 早于2 .6 .27版本, available的值则同free一样。

[ rootaegon ~ ]# man free # 看一眼写的清清楚楚
 used   Used memory (calculated as total - free - buffers - cache)  #应用程序真正使用的内存

释放内存举例


[root@localhost ~]# free #显示Linux系统中空闲的、已用的物理内存及swap内存,以及被内核使用的buffer
             total        used        free      shared  buff/cache   available
Mem:        1965960       94376     1731484        8752      140100     1709736
Swap:       1952764           0     1952764

[root@localhost ~]# echo 3 > /proc/sys/vm/drop_caches #释放内存
[root@localhost ~]# free
             total        used        free      shared  buff/cache   available
Mem:        1965960       90280     1805604        8816       70076     1748752
Swap:       1952764           0     1952764

内核启动参数 :/proc/cmdline

[root@localhost ~]# cat /proc/cmdline 
BOOT_IMAGE=/vmlinuz-3.10.0-693.el7.x86_64 root=UUID=459bd90a-e904-4505-a79a-fee152337270 ro rhgb quiet LANG=zh_CN.UTF-8

[root@localhost ~]# uptime #top第一行
12:03:58 up  1:48,  2 users, load average: 0.00, 0.01, 0.05

注意:当我们卸载/proc后

[root@localhost ~]# umount /proc -l  #卸载proc文件系统
#下述命令du不可用
free -m
uptime
lscpu
toop

[root@localhost ~]# mount -t proc proc /proc/ #重新挂载
-t proc 指定文件系统的类型
proc 文件系统,虚拟文件系统
/proc 挂载点

 

后台进程管理

什么是后台进程?

通常进程都会在终端前台运行,但是一旦关闭终端,进程也会随着结束,那么此时我们就希望进程能在后台运行,就是将在前台运行的进程放到后台运行,这样即使我们关闭了终端也不影响进程的正常运行。


为什么要把进程放到后台运行

企业中很多时候会有一些需求: 1.传输大文件,由于网络问题需要传输很久 2.我们之前的国外业务,国内到国外,网速很慢,我们需要选择节点做跳板机,那么就必须知道,哪个节点到其他地区网速最快,丢包率最低。 3.有些服务没有启动脚本,那么我们就需要手动运行,并把他们放到后台


使用什么工具可以把进程放到后台

早期的时候,大家都选择使用&,将进程放到后台运行,然后再使用jobsbgfg等方式查看进程状态,太麻烦了,也不只管,所以我们推荐使用screennohup

作业控制是一个命令行功能,允许一个 shell 实例来运行和管理多个命令。 如果没有作业控制,父进程 fork()一个子进程后,将 sleeping,直到子进程退出。 使用作业控制,可以选择性暂停,恢复,以及异步运行命令,让 shell 可以在子进程运行期间返回接受其 他命令。

前台进程,后台进程jobs,bg,fg ctrl + Z , ctrl +c , ctrl + B

[root@zls ~]# sleep 3000 & #运行程序(时),让其在后台执行 
[root@zls ~]# sleep 4000 //^Z,将前台的程序挂起(暂停)到后台
[2]+ Stopped sleep 4000
[root@zls ~]# ps aux |grep sleep
[root@zls ~]# jobs //查看后台作业
[1]- Running sleep 3000 &
[2]+ Stopped sleep 4000

[root@zls ~]# bg %2     //让作业 2 在后台运行
[root@zls ~]# fg %1     //将作业 1 调回到前台
[root@zls ~]# kill %1   //kill 1,终止 PID 为 1 的进程

[root@zls ~]# (while :; do date; sleep 2; done) & //进程在后台运行,但输出依然在当前终端
[root@zls ~]# (while :; do date; sleep 2; done) &>/dev/null &

screen

#安装screen命令
[root@zls ~]# yum install -y screen

#安装redis
[root@zls ~]# yum install -y redis

#启动redis
[root@zls ~]# redis-server

#放到后台ctrl + z
[1]+  已停止               redis-server

#关闭终端,redis进程就没有了

#下载mysql安装包
[root@zls ~]# wget https://downloads.mysql.com/archives/get/file/mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz

#使用screen
[root@zls ~]# screen -S download_mysqld
#ctrl + a + d放置后台
[detached from 3567.download_mysqld]
#查看screen列表
[root@zls ~]# screen -list
There is a screen on:
   3567.download_mysqld   (Detached)
1 Socket in /var/run/screen/S-root.

#打开screen终端
[root@zls ~]# screen -r 3567

管道

管道是一种通信机制,通常用于进程间的通信(也可通过socket进行网络通信),它表现出来的形式将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)。

[root@localhost ~]# ps aux |grep "httpd"
[root@localhost ~]# yum list |grep nginx

详细地说, 管道操作符号 "|" , 主要用来连接左右两个命令, 将左侧的命令的标准输出, 交给右侧命令的标准输入

PS: 无法传递标准错误输出至后者命令

格式: cmd1 | cmd2 [...|cmdn]

管道流程示意图

image-20201107161229904

管道应用实例

  • 统计当前etc/passwd中用户使用的shell类型

[root@localhost ~]# awk -F: '{print $7}' /etc/passwd | sort |uniq -c
      1 /bin/bash
      1 /bin/sync
      1 /sbin/halt
     15 /sbin/nologin
      1 /sbin/shutdown
  • 统计网站的访问情况

    [root@localhost ~]# netstat -an |grep :80 |awk -F":" '{print $8}'|sort |uniq -c
  • 打印所有IP

    [root@localhost ~]# ip addr |grep 'inet ' |awk '{print $2}' |awk -F"/" '{print$1}'
    127.0.0.1
    192.168.146.168
  • 打印根分区已用空间的百分比(仅打印数字)

    [root@localhost ~]# df -P|grep '/$' |awk '{print $5}'|awk -F"%" '{print $1}'
    6

     

  • 统计网站访问最多的IP top10

    #思路:打印所有访问的过来IP |排序|去重|倒序排序|取前10
    [root@egon ~]# awk '{print $1}' access.log |sort |uniq -c |sort -rn|head
    12049 58.220.223.62
    10856 112.64.171.98
    1982 114.83.184.139
    1662 117.136.66.10
    1318 115.29.245.13
    961 223.104.5.197
    957 116.216.0.60
    939 180.111.48.14
    871 223.104.5.202
    869 223.104.4.139

     

管道双向重定向命令:tee

  • tee:在数据流的处理过程中将某段信息保存下来,使其既能输出到屏幕又能保存到某一个文件中。

  • 选项:-a #追加

  • 重定向与tee他们在使用过程中有什么区别

    [root@localhost ~]# ifconfig >1.txt #直接将内容写入1.txt文件中
    [root@localhost ~]# ifconfig |tee 2.txt #命令执行会输出之屏幕,但同时保存一份至2.txt文件中
  • xargs参数传递, 主要让一些不支持管道的命令可以使用管道技术

    [root@egon ~]# which cat|xargs ls -l
    [root@egon ~]# ls |xargs rm -fv
    [root@egon ~]# ls |xargs cp -rvt /tmp/ -或-> ls | xargs -I {} cp -rv {} /tmp/
    [root@egon ~]# ls |xargs mv -t /tmp/ -或-> ls | xargs -I {} mv {} /tmp

     

僵尸进程与孤儿进程

引入

僵尸进程是杀不死的, 是因为它已经死了, 否则怎么叫Zombie (僵尸) 呢? 冤魂不散, 自然是生前有结未解之故。在ࣁUNIX/Linux中, 每个进程都有一个父进程, 进程号叫PID(Process ID), 相应地, 父进程号就叫PPID(Parent PID)。当进程死亡时, 它会自动关闭已打开的文件, 舍弃已占用的内存、交换空间等等系统资源, 然后向其父进程返回一个退出状态值, 报告死讯。如果程序有 bug, 就会在这最后一步出问题。儿子说我死了, 老子却没听见, 没有及时收棺入殓, 儿子便成了僵尸......

僵尸进程

  • 什么是僵尸进程

    操作系统负责管理进程
    我们的应用程序若想开启子进程, 都是在向操作系统发送系统调用
    当一个子进程开启起来以后, 它的运行与父进程是异步的, 彼此互不影响, 谁先死都不一定

    linux 操作系统的设计规定: 父进程应该具备随时获取子进程状态的能力
    如果子进程先于父进程运行完毕, 此时若linux 操作系统立刻把该子进程的所有资源全部释放掉, 那么父进程来查看子进程状态时, 会突然发现自己刚刚生了一个儿子, 但是儿子没了! ! !
    这就违背了linux 操作系统的设计规定
    所以, linux 系统出于好心, 若子进程先于父进程运行完毕/死掉, 那么linux 系统在清理子进程的时候, 会将子进程占用的重型资源都释放掉( 比如占用的内存空间、cpu资源、打开的文件等) , 但是会保留一部分子进程的关键状态信息, 比如进程号the process ID , 退出状态the termination status of the process, 运行时间the amount of cPU time taken b2 the process等, 此时子进程就相当于死了但是没死干净, 因而得名" 僵尸进程" , 其实僵尸进程是linux 操作系统出于好心, 为父进程准备的一些子进程的状态数据, 专门供父进程查阅, 也就是说" 僵尸进程" 是linux 系统的一种数据结构, 所有的子进程结束后都会进入僵尸进程的状态
  • 那么问题来了, 僵尸进程残存的那些数据不需要回收吗? ? ?

    当然需要回收了, 但是僵尸进程毕竟是linux 系统出于好心, 为父进程准备的数据, 至于回收操作, 应该是父进程觉得自己无需查看僵尸进程的数据了, 父进程觉得留着僵尸进程的数据也没啥用了, 然后由父进程发起一个系统调用wait / waitpid来通知linux 操作系统说: 哥们, 谢谢你为我保存着这些僵尸的子进程状态, 我现在用不上他了, 你可以把他们回收掉了。然后操作系统再清理掉僵尸进程的残余状态, 你看, 两者配合的非常默契, 但是, 怕就怕在。。。
  • 分三种情况讨论

    1、linux 系统自带的一些优秀的开源软件, 这些软件在开启子进程时, 父进程内部都会及时调用wait/waitpid来通知操作系统回收僵尸进程, 所以, 我们通常看不到优秀的开源软件堆积僵尸进程, 因为很及时就回收了, 与linux 系统配合的很默契
    2、一些水平良好的程序员开发的应用程序, 这些程序员技术功底深厚, 知道父进程要对子进程负责, 会在父进程内考虑调用wait/waitpid来通知操作系统回收僵尸进程, 但是发起系统调用wait/waitpid的时间可能慢了些, 于是我们可以在linux 系统中通过命令查看到僵尸进程状态
    [root@egon ~]# ps aux | grep [Z]+
    3、一些垃圾程序员, 技术非常垃圾, 只知道开子进程, 父进程也不结束, 就在那傻不拉几地一直开子进程, 也压根不知道啥叫僵尸进程, 至于wait/waitpid的系统调用更是没听说过, 这个时候, 就真的垃圾了, 操作系统中会堆积很多僵尸进程, 此时我们的计算机会进入一个奇怪的现象, 就是内存充足、硬盘充足、cpu空闲, 但是, 启动新的软件就是无法启动起来, 为啥, 因为操作系统负责管理进程, 每启动一个进程就会分配一个pid号, 而pid号是有限的, 正常情况下pid也用不完, 但怕就怕堆积一堆僵尸进程, 他吃不了多少内存, 但能吃一堆pid

    如何清理僵尸进程?

    针对情况3 , 只有一种解决方案, 就是杀死父进程, 那么僵尸的子进程会被linux 系统中pid为1的顶级进程
    (init或s2stemd) 接管, 顶级进程会定期发起系统调用wait/waitpid来通知操作系统清理僵尸

    针对情况2 , 可以发送信号给父进程, 通知它快点发起系统调用wait/waitpid来清理僵尸的儿子
    kill -cH工D 父进程PID

    杀死僵尸进程解决办法

    解决办法:

    (1)如果业务不繁忙,允许停机,可以使用重启机器来解决(这种方法不行,业务不能停)

    (2)杀掉父进程(由于是namenode进程,如果是HA模式,杀掉后会切换到另个nn节点)(未采取,我们找的是根本原因)

    kill -9 父进程号     //注意:如果这个父进程号是init进程,杀掉它,整个系统就挂了

    对于此种方法,虽然能暂时解决本台机器上的僵尸进程,如果没有找到致使僵尸进程的根本原因,就算切到了另个nn节点,另个nn节点也会出现僵尸异常进程的。

    (3)将筛选到的僵尸子进程进行挂起(未采取,但其他情况可以使用)

    kill -HUP 进程pid     //将子进程挂起后,相当于什么也不做了

    僵尸进程常用命令总结:

    常用命令总结:

    top   //查看里面的zombie对应的进程有多少个

    ps -e -o ppid,stat | grep Z | cut -d " " -f2 | wc -l  //统计僵尸进程的个数

    ps -ef | grep "defunct"   //可以看到僵尸进程的父进程号

    如果要杀掉僵尸进程,需要杀掉它的父进程号,命令为:

    kill -9 父进程号     //注意:如果这个父进程号是init进程,杀掉它,整个系统就挂了,所以考虑使用下面这个命令

    kill -HUP 进程pid    //将筛选到的子进程挂起

    结语

    僵尸进程是linux 系统出于好心设计的一种数据结构, 一个子进程死掉后, 相当于操作系统出于好心帮它的爸爸保存它的遗体, 之说以会在某种场景下有害, 是因为它的爸爸不靠谱, 儿子死了, 也不及时收尸( 发起系统调用让操作系统收尸)
    说白了, 僵尸进程本身无害, 有害的是那些水平不足的程序员, 他们总是喜欢写bug,

    僵尸进程危害

    由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 那么会不会因为父进程太忙来不及wait子进程,或者说不知道 子进程什么时候结束,而丢失子进程结束时的状态信息呢? 不会。因为UNⅨ提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放. 但这样就导致了问题,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
    # 总结:僵尸进程会占用大量pid,对硬盘、cpu、内存几乎不受影响。

    代码演示

    from multiprocessing import Process
    import time
    import os

    def task():
      print("son->%s" %os.getpid())
      time.sleep(7)
       
    if __name__ == "__main__":
       for i in range(3):
           p=Process(target=task)
    p.start()
     
      print("father->%s" %os.getpid())
      time.sleep(10000)
       
       
       
    1.执行python文件,输出结果
    [root@oldboy ~]# python test.py &
    [1] 41789
    [root@oldboy ~]# son->41790
    son->41791
    father->41789
    son->41792

    2.杀死父进程
    [root@localhost ~]# kill -9 41789

    3.子进程已经被pid为1的顶级进程接受了,所以僵尸进程在这种情况下是不存在的,存在的只有孤儿进程而已,孤儿进程申明周期结束自然会被顶级进程来销毁

    [root@oldboy ~]# ps -elf |grep python
    4 S root       9561      1  0  80   0 - 143574 poll_s 20:06 ?       00:00:00 /usr/bin/python2 -Es /usr/sbin/tuned -l -P
    0 S root      41795   5055  0  80   0 - 28206 pipe_w 20:54 pts/2    00:00:00 grep --color=auto python
    [1]+ 已杀死               python test.py

     

孤儿进程

父进程先死掉, 而它的一个或多个子进程还在运行, 那么那些子进程将成为孤儿进程。孤儿进程将被进程号为1的顶级进程 (init或s2stemd) 所收养, 并由顶级进程对它们完成状态收集工作。
进程就好像是一个民政局, 专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候, 内核就把孤儿进程的父进程设置为顶级进程, 而顶级进程会循环地wait( )它的已经退出的子进程。这样, 当一个孤儿进程凄凉地结束了其生命周期的时候, 顶级进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

总结: 当父进程先于子进程结束时, 子进程会被顶级进程收养, 成为孤儿进程。

 

原文地址:https://www.cnblogs.com/taoxiaoxin/p/13942437.html