Fork me on GitHub

-linux-进程管理

一 进程介绍

程序:存放代码的文件 (静态)

进程:程序的运行过程 (动态)

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

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

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

注意:如果父进程终止,子进程也会随之被终止 (守护进程)

[root@arther-linux ~]# yum install nginx -y
[root@arther-linux ~]# systemctl start nginx
[root@arther-linux ~]# ps aux |grep nginx
root      2037  0.0  0.0 112824   980 pts/0    S+   18:37   0:00 grep --color=auto ngin

1 进程-进程状态(R、S、D、T、Z、X)

进程概念

  • 正在执行的程序
  • 正在计算机执行的程序实例
  • 能分配处理器并有处理器执行的实体

进程的两个基本元素是程序代码和代码想关联的数据集。进程是一种动态描述,但并不代表所有的进程都在执行。这就可以引入进程状态。

进程在内存中因策会略或调度需求,

会处于各种状态:

Linux下的进程状态

static const char * const task_state_array[] = { 
"R (running)", /* 0 */ 
"S (sleeping)", /* 1 */ 
"D (disk sleep)", /* 2 */ 
"T (stopped)", /* 4 */ 
"t (tracing stop)", /* 8 */ 
"X (dead)", /* 16 */ 
"Z (zombie)", /* 32 */ 
};

# R- 可执行状态(运行状态)
只有在运行状态的进程才有可能在CPU上运行,注意是可能,并不意味着进程一定在运行中。同一时刻可能有 多个进程处在可执行状态,这些进程的PCB(进程控制块)被放入对应CPU的可执行队列中。然后进程调度器 从各个可执行队列中分别选择一个进程在CPU上运行。 另外如果计算机只有一个处理器,那么一次最多只有一个进程处于这种状态。
(在此状态下等待被cpu调用)

# S- -可中断睡眠状态(sleeping) 
处在这个状态意味着进程在等待事件完成。这些进程的PCB(task_struct结构)被放入对应时间的等待队列 中。然后等待的事件发生时,对应的进程将被唤醒。

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

# T- -暂停状态 
给进程发送一个SIGSTOP信号,进程就会响应信号进入T状态,除非该进程正处在D状态。 再通过发送SIGCONT信号让进程继续运行。 
kill -SIGSTOP 
kill -SIGCONT

# Z- -僵死状态 
僵死状态是一个比较特殊的状态。进程在退出的过程中,处于TASK_DEAD状态。 在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进 程就只剩下task_struct这么个空壳,故称为僵尸。 
X- -死亡状态或退出状态(dead) 
死亡状态是内核运⾏ kernel/exit.c ⾥的 do_exit() 函数返回的状态。这个状态只是⼀个返回状态, 你不会在任务列表⾥看到这个状态
(pid没有被回收,还占用着cpu资源)

进程状态切换

进程在运行中不断的改变运行状态;

  • 就绪状态

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

  • 执行(Running)状态

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

  • 阻塞(Blocked)状态

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

就绪–>执行
处在就绪状态的进程,当调度器为其分配了处理机后,就变成了执行状态。

执行–>就绪
执行状态的进程在其执行过程中,时间片跑完了不得不让出处理机,于是从执行变成就绪状态。

执行–>阻塞
正在执行的进程等待某种事件而无法继续执行时,便从执行状态变成阻塞状态。

阻塞–>就绪
处在阻塞状态的进程,如果等待的时间发生,则从阻塞状态转变成就绪状态。

二 查看进程

ps aux是常用组合,查看进程用户、PID、占用CPU百分比、占用内存百分比、状态、执行的命令等。

-a 				# 显示一个终端的所有进程

-u				# 选择有效的用户id或者是用户名

-x				# 显示没有控制终端的进程,同时显示各个命令的具体路径

示例

[root@arther-linux ~]# ps aux |head -5
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3 128816  7392 ?        Ss   05:17   0:17 /usr/lib/systemd/systemd --system --deserialize 15
root         2  0.0  0.0      0     0 ?        S    05:17   0:00 [kthreadd]
root         4  0.0  0.0      0     0 ?        S<   05:17   0:00 [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        S    05:17   0:00 [ksoftirqd/0]

查看结果显示

USER:				运行进程的用户
  
PID:				进程ID
  
%CPU:				CPU占用率
  
%MEN:				内存占用率
  
VSZ:				占用虚拟内存,单位:kb
    				VSZ是指已分配的线性空间大小,这个大小通常并不等于程序实际用到的内存大						小,产生这个的可 能性很多 比如内存映射,共享的动态库,或者向系统申请了						更多的堆,都会扩展线性空间大小。
      
RSS:				占用实际内存,单位:kb
    				RSZ是Resident Set Size,常驻内存大小,即进程实际占用的物理内存大小
      
TTY:				进程运行的终端
  
STAT:				进程状态
  					R 运行 
    				S 可中断睡眠 
      			Sleep,即在睡眠的过程中可以接收信号唤醒=》执行的IO操作可以得到硬件设 						 备的响应
        		D 不可中断睡眠,即在睡眠的过程中不可以接收信号唤醒=》执行的IO操作得不						 到硬件设备的响应 
          	T 停止的进程 
            Z 僵尸进程 
            X 死掉的进程(几乎看不见,因为死了就立即回收了) 
            < 标注了<小于号代表优先级较高的进程 
            N N代表优先级较低的进程 
            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+Z 都无济于,因为它们压根儿就 不受这些信号的支配。 

# 解释 
进程为什么会被置于D状态呢?处于uninterruptible sleep状态的进程通常是在等待IO,比如磁盘IO, 网络IO,其他外设IO,如果进程正在等待的IO在较长的时间内都没有响应,那么就很会不幸地被ps看到了, 同时也就意味着很有可能有IO出了问题,可能是外设本身出了故障,也可能是比如NFS挂载的远程文件系统已 经不可访问了。 正是因为得不到IO的响应,进程才进入了uninterruptible sleep状态,所以要想使进程从 uninterruptible sleep状态恢复,就得使进程等待的IO恢复,比如如果是因为从远程挂载的NFS卷不可 访问导致进程进入uninterruptible sleep状态的,那么可以通过恢复该NFS卷的连接来使进程的IO请求 得到满足,除此之外,要想干掉处在D状态进程就只能重启整个Linux系统了(恐怖的D状态)。

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

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

示例

-1.在窗口1执行vim命令
[root@arther-linux /]# vim 1.txt 

-2.在窗口2查看vim的运行状态为:S+
[root@arther-linux ~]# ps aux |grep [v]im
root      8065  0.1  0.2 149620  5188 pts/0    S+   17:50   0:00 vim 1.txt
    
-3.在窗口1执行:ctrl+z,将进程放置到后台
[root@egon ~]# vim egon.txt 
[4]+ 已停止 vim egon.txt

-4.在窗口2查看vim的运行状态为:T
[root@egon ~]# ps aux |grep [v]im root 
103231 0.3 0.2 149828 5460 pts/2 T 17:48 0:00 vim egon.txt

查看进程树

[root@arther-linux /]# pstree

查看ppid

[root@arther-linux /]# ps -ef | head -10
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 05:17 ?        00:00:17 /usr/lib/systemd/systemd --system --deserialize 15
root         2     0  0 05:17 ?        00:00:00 [kthreadd]
root         4     2  0 05:17 ?        00:00:00 [kworker/0:0H]
root         6     2  0 05:17 ?        00:00:00 [ksoftirqd/0]
root         7     2  0 05:17 ?        00:00:01 [migration/0]
root         8     2  0 05:17 ?        00:00:00 [rcu_bh]
root         9     2  0 05:17 ?        00:00:20 [rcu_sched]
root        10     2  0 05:17 ?        00:00:00 [lru-add-drain]
root        11     2  0 05:17 ?        00:00:00 [watchdog/0]

动态查看

-1.基本用法
[root@arther-linux /]# top
[root@arther-linux /]# top -d 1 # 1秒查看一次

三 管理进程

1 关于HUP信号

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

在 Unix 的早期版本中,每个终端都会通过 modem 和系统通讯。 
当用户 logout 时,modem 就会挂断(hang up)电话。 
同理,当 modem 断开连接时,就会给终端发送 hangup 信号来通知其关闭所有子进程。

综上,我们知道,当用户注销(logout)或者网络断开或者终端关闭(注意注意注意,一定是终端整体关闭,不是单纯的exit)时,终端都会收到Linux HUP信号(hangup)信号,然后终端在结束前会关闭其所有子进程。如果我们想让我们的进程在后台一直运行,不要因为用户注销(logout)或者网络断开或者终端关闭而一起被干掉,那么我们有两种解决方案。

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

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

2 nohup命令

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

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

3 screen命令

# 1、安装 [root@egon ~]# yum install screen -y 

# 2、运行命令 
方式一:开启一个窗口并用-S指定窗口名,也可以不指定 
[root@egon ~]# screen -S egon_dsb 
''' Screen将创建一个执行shell的全屏窗口。你可以执行任意shell程序,就像在ssh窗口中那样。 在该窗口中键入exit则退出该窗口,如果此时,这是该screen会话的唯一窗口,该screen会话退出,否则 screen自动切换到前一个窗口。 
''' 

方式二:Screen命令后跟你要执行的程序 
[root@egon ~]# screen vim test.txt

''' 
Screen创建一个执行vim test.txt的单窗口会话,退出vim将退出该窗口/会话。
'''
# 3、原理分析 
screen程序会帮我们管理运行的命令,退出screen,我们的命令还会继续运行,若关闭screen所在的终 端,则screen程序的ppid变为1,所以screen不会死掉,对应着它帮我们管理的命令也不会退出 测试略 

# 4:重新连接会话 
在终端1中运行 
[root@egon ~]# screen 
[root@egon ~]# n=1;while true;do echo $n;sleep 1;((n++));done 
[root@egon ~]# 按下ctrl+a,然后再按下ctrl+d,注意要连贯,手别哆嗦, 
[root@egon ~]# 此时可以关闭整个终端,我们的程序并不会结束 

打开一个新的终端 
[root@egon ~]# screen -ls 
There is a screen on: 
  109125.pts-0.egon (Detached) 
1 Socket in /var/run/screen/S-root. 

[root@egon ~]# screen -r 109125 # 会继续运行 
[root@egon ~]# 

注意:如果我们刚开始已经用screen -S xxx指定了名字,那么我们其实可以直接 screen -r xxx ,就无须去找进程id了
posted @ 2020-12-11 19:28  artherwan  阅读(66)  评论(0编辑  收藏  举报