Linux 进程与工作

1. 实验介绍

1.1 实验内容

Linux 中同样存在程序挂掉,程序出问题的情况,为了能够对其进一步的控制,我们将在本实验对进程的基础知识与进程的查看、控制命令进行学习。

1.2 实验知识点

  • 进程的关系
  • 工作的管理
  • 进程的状态
  • 进程的控制
  • 进程的执行顺序

1.3 推荐阅读

2. 进程的关系

为了能够在出现异常的时候对一个程序做更准确的控制,为了能够在查看进程信息指标的时候作出更准确的判断,我们需要先了解进程的用途与之间的关系。

举一例子:

就比如我们启动了终端,就是启动了一个 zsh 进程(zsh 是类似与 bash 的shell,用起来比 bash 更方便,环境中默认让大家使用 zsh),我们可以在 zsh 中再输入 zsh 则会再启动一个 zsh 的进程,此时第二个 zsh 进程就是由第一个 zsh 进程创建出来的。

我们一般称呼第一个 zsh 进程是第二 zsh 进程的父进程,第二 bash 进程是第一个 bash 进程的子进程。

既然子进程是通过父进程而衍生出来的,那么子进程的推出与资源的回收定然与父进程有很大的相关性。当一个子进程要正常的终止运行时,或者该进程结束时它会向父进程传递一个 SIGCHLD 信号,父进程做最后的资源回收与收尾工作。

还有一些特殊的情况会产生一些特殊的进程:

  • 僵尸进程
  • 孤儿进程
  • 内核初始化进程

什么事僵尸进程呢?任务完成的子进程其代码执行部分已经结束执行了,系统的资源也基本归还给系统了,但其父进程没有做最后的收尾工作,导致进程的进程控制块(PCB)仍驻留在内存中,而它的 PCB 的存在代表这个进程还存在(因为 PCB 就是进程存在的唯一标志,里面有 PID 等消息),并没有消亡,这样的进程称之为僵尸进程(Zombie)。

如图中第四列标题是 S,S 表示的是进程的状态,而在下属的第三行的 Z 表示的是 Zombie 的意思。(ps 命令将在后续详解)。图中只是为了展示僵尸进程,并不需要执行该命令。

什么是孤儿进程呢?如果父进程结束(非正常的结束),未能及时收回子进程,子进程仍在运行,这样的子进程称之为孤儿进程。在 Linux 系统中,孤儿进程一般会被 init 进程所"收养",称为 init 的子进程,由 init 来做善后处理。

进程 0 是系统引导时创建的一个特殊进程,也称之为内核初始化,其最后一个动作就是创建一个子进程运行 /sbin/init 可执行文件,该子进程就是 PID=1 的进程 1,而进程 0 就转为交换进程(也被称为空闲进程),进程 1(init 进程)是第一个用户态的进程,再由它不断创建系统里其他的进程,所以它是所有用户态进程的父进程或者祖先进程。同时它是一个守护程序,直到计算机关机才会停止。

通过以下的命令我们可以很明显的看到这样的结构

pstree

或者从此图我们可以更加形象的看清子父进程的关系

我们还可以使用这样一个命令来看,其中 pid 就是该进程的一个唯一编号,ppid 就是该进程的父进程的 pid,command 表示的是该进程通过执行什么样的命令或者脚本而运行:

ps -fxo user,ppid,pid,pgid,command

可以在图中看见我们执行的 ps 就是由 zsh 创建的子进程而执行的。

使用这样的一个命令我们也能清楚的看见 init 如上文所说是由进程 0 这个初始化进程来创建而出的子进程,而其他的进程基本是由 init 创建的子进程,或者是由子进程创建出来的子进程。所以 init 是用户进程的第一个进程也是所有用户进程的父进程或者祖先进程。(ps 命令将在后续课程详解)

了解进程关系,进一步我们会对不同用途功能的进程做分类,一般我们以这样两个角度来分类进程:

  • 进程的功能与服务的对象:
    • 用户进程:执行用户程序、应用程序或者说内核之外的程序而产生的进程,此类进程可以在用户的控制下运行或关闭。
    • 系统进程:通过执行系统内核程序而产生的进程,比如可以执行内存资源分配和进程切换等相对底层的工作;而且该进程的运行不受用户的干预,即使是 root 用户也不能干预系统进程的运行。
  • 应用程序的服务类型:
    • 交互进程:在执行过程中,需要与用户进行交互操作
    • 批处理进程:该进程是一个进程集合,负责按顺序启动其他的进程。
    • 守护进程:守护进程是一直运行的一种进程,它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。例如 httpd 进程,还有经常用的 cron(在 centOS 系列为 crond)进程,这个进程为 crontab 的守护进程,可以周期性的执行用户设定的某些任务。

4. 工作管理

进程直接的父子关系只能描述比较浅的关系,若是同父进程的进程,并不能很好的描述,所以引入了进程组的概念,每一个进程都会是一个进程组的成员,而且这个进程组是唯一存在的,以 PGID(process group ID)字段来描述,而每当一个进程被创建的时候,它便会成为其父进程所在组中的一员。

一般情况,进程组的 PGID 等同于进程组的第一个成员的 PID,并且这样的进程称为该进程组的领导者,也就是领导进程,领导进程可以先终结,此时进程组依然存在,并持有相同的 PGID,直到进程组中最后一个进程终结。

与进程组类似,每当一个进程被创建的时候,它便会成为其父进程所 Session 中的一员,每一个进程组都会在一个 Session 中,并且这个 Session 是唯一存在,

Session 主要是针对一个 tty 建立,Session 中的每个进程都称为一个工作(job)。每个会话可以连接一个终端(control terminal)。当控制终端有输入输出时,都传递给该会话的前台进程。Session 意义在于将多个 jobs 囊括在一个终端,并取其中的一个 job 作为前台,来直接接受该终端的输入输出以及终端信号,其他 jobs 在后台运行。

前台(foreground)就是在终端中运行,能与你有交互的进程。

后台(background)就是在终端中运行,但是你并不能与其任何的交互,也不会显示其执行的过程

前台工作就像做饭的时候你正在切菜没切完你不会去做其他的,而后台工作就像你在切菜之前你让电饭煲帮你煮饭,锅里煮着汤,这些不会影响你当前做的事情,但是他们在运行着。

那如何将一个进程放入后台运行呢?只需要在执行命令的后面增加一个 & 符号即可。例如:

ls &

图中所显示的 [1] 236 分别是该 job 的 job number 与该进程的 PID,而最后一行的 Done 表示该命令已经在后台执行完毕。

我们还可以通过 ctrl + z 使我们的当前的前台工作停止并丢到后台中去

tail -f /var/log/dpkg.log

被停止并放置在后台的工作我们可以使用这个命令来查看

jobs
tail -f /var/log/dpkg.log
jobs
tail -f /var/log/dpkg.log
jobs

  • 第一列显示的为被放置后台 job 的编号
  • 第二列的 + 表示最近(刚刚、最后)被放置后台的 job,同时也表示预设的工作,也就是若是有什么针对后台 job 的操作,首先对预设的 job,- 表示倒数第二(也就是在预设之前的一个)被放置后台的工作,倒数第三个(再之前的)以后都不会有这样的符号修饰,第三列表示它们的状态,而最后一列表示该进程执行的命令

我们可以通过这样的一个命令将后台的工作拿到前台来

# 后面不加参数提取预设工作,加参数提取指定工作的编号
# ubuntu 在 zsh 中需要 %,在 bash 中可有可无 %
fg [%jobnumber]
fg

fg %2

之前我们通过 ctrl + z 使得工作停止放置在后台,若是我们想让其在后台运作我们就使用这样一个命令

# 与fg类似,加参则指定,不加参则取预设
bg [%jobnumber]
fg %2
jobs
bg %2
jobs
bg
jobs

既然有方法将被放置在后台的工作提至前台或者让它从停止变成继续运行在后台,当然也有方法删除一个工作,或者重启等等

# kill的使用格式如下
kill -signal %jobnumber

# signal 从1-64个信号值可以选择,可以这样查看
kill -l

其中常用的有这些信号值

信号值 作用
-1 重新读取参数运行,类似与restart
-2 如同 ctrl + c 的操作退出
-9 强制终止该任务
-15 正常的方式终止该任务

图片中命令不用输入

注意:

若是在使用 kill + 信号值然后直接加 pid,你将会对 pid 对应的进程进行操作

若是在使用 kill + 信号值然后加 %jobnumber,这时所操作的对象是 job,这个数字就是当前 bash 中后台的运行的 job 的 ID

5. 进程的状态

工作可以说是简略版的进程信息与状态查看,因为他是局限在当前的 bash 或者 zsh session 中的进程控制,接下来我们便学习如何查看整个系统进程运行状态。

5.1 top 工具

top 工具可以说是最为常用的进程查看工具之一了,它能够实时、动态的显示当前系统中进程的信息。(实时、动态表示信息每秒都不一样,随时变化跟进最新的信息)

top

top 是一个在前台执行的程序,所以执行后便进入到这样的一个交互界面,正是因为交互界面我们才可以实时的获取到系统与进程的信息。在图中为我们罗列了很多的信息,下面为大家一一解说一下:

我们看到 top 显示的第一排

内容 解释
top 表示当前程序的名称
11:05:18 表示当前的系统的时间
up 8 days,17:12 表示该机器已经启动了多长时间
1 user 表示当前系统中只有一个用户
load average:0.29,0.20,0.25 分别对应1、5、15分钟内cpu的平均负载

load average 在 wikipedia 中的解释是 the system load is a measure of amount of work that a computer system is doing 也就是对当前 CPU 工作量的度量,具体来说也就是指运行队列的平均长度,也就是等待 CPU 的平均进程数相关的一个计算值。

我们该如何看待这个 load average 数据呢?

假设我们的系统是单 CPU、单内核的,把它比喻成是一条单向的桥,把 CPU 任务比作汽车。

  • load = 0 的时候意味着这个桥并没有车,cpu 没有任何任务;
  • load < 1 的时候意味着桥上的车并不多,一切都还是很流畅的,cpu 的任务并不多,资源还很充足;
  • load = 1 的时候就意味着桥已经被车给占满了,没有一点空隙,cpu 的已经在全力工作了,所有的资源都被用完了,当然还好,这还在能力范围之内,只是有点慢而已;
  • load > 1 的时候就意味着不仅仅是桥上已经被车占满了,就连桥外都被占满了,cpu 已经在全力的工作了,系统资源的用完了,但是还是有大量的进程在请求,在等待。若是这个值大于2,大于3,超过 CPU 工作能力的 2,3。而若是这个值 > 5 说明系统已经在超负荷运作了。

这是单个 CPU 单核的情况,而实际生活中我们需要将得到的这个值除以我们的核数来看。我们可以通过一下的命令来查看 CPU 的个数与核心数

# 查看物理 CPU 的个数
cat /proc/cpuinfo |grep "physical id"|sort |uniq|wc -l

# 每个cpu的核心数
cat /proc/cpuinfo |grep "physical id"|grep "0"|wc -l

通过上面的指数我们可以得知 load 的临界值为 1,但是在实际生活中,比较有经验的运维或者系统管理员会将临界值定为0.7。通常我们都会先看 15 分钟的值来看这个大体的趋势,然后再看 5 分钟的值对比来看是否有下降的趋势。

top 的第二行数据,基本上第二行是进程的一个情况统计

内容 解释
Tasks:26 total 进程总数
1 running 1个正在运行的进程数
25 sleeping 25个睡眠的进程数
0 stopped 没有停止的进程数
0 zombie 没有僵尸进程数

来看 top 的第三行数据,这一行基本上是 CPU 的一个使用情况的统计了

内容 解释
Cpu(s)1.0%us 用户空间进程占用CPU百分比
1.0% sy 内核空间运行占用CPU百分比
0.0%ni 用户进程空间内改变过优先级的进程占用CPU百分比
97.9%id 空闲CPU百分比
0.0%wa 等待输入输出的CPU时间百分比
0.1%hi 硬中断(Hardware IRQ)占用CPU的百分比
0.0%si 软中断(Software IRQ)占用CPU的百分比
0.0%st (Steal time) 是 hypervisor 等虚拟服务中,虚拟 CPU 等待实际 CPU 的时间的百分比

CPU 利用率是对一个时间段内 CPU 使用状况的统计,通过这个指标可以看出在某一个时间段内 CPU 被占用的情况,而 Load Average 是 CPU 的 Load,它所包含的信息不是 CPU 的使用率状况,而是在一段时间内 CPU 正在处理以及等待 CPU 处理的进程数情况统计信息,这两个指标并不一样。

来看 top 的第四行数据,这一行基本上是内存的一个使用情况的统计了:

内容 解释
8176740 total 物理内存总量
8032104 used 使用的物理内存总量
144636 free 空闲内存总量
313088 buffers 用作内核缓存的内存量

注意

系统的中可用的物理内存最大值并不是 free 这个单一的值,而是 free + buffers + swap 中的 cached 的和

来看 top 的第五行数据,这一行基本上是交换区的一个使用情况的统计了

内容 解释
total 交换区总量
used 使用的交换区总量
free 空闲交换区总量
cached 缓存的交换区总量,内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖

在下面就是进程的一个情况了

列名 解释
PID 进程id
USER 该进程的所属用户
PR 该进程执行的优先级 priority 值
NI 该进程的 nice 值
VIRT 该进程任务所使用的虚拟内存的总数
RES 该进程所使用的物理内存数,也称之为驻留内存数
SHR 该进程共享内存的大小
S 该进程的状态:S=sleep R=running Z=zombie
%CPU 该进程CPU的利用率
%MEM 该进程内存的利用率
TIME+ 该进程活跃的总时间
COMMAND 该进程运行的名字

注意:

NICE 值叫做静态优先级,是用户空间的一个优先级值,其取值范围是 -20 至 19。这个值越小,表示进程"优先级"越高,而值越大"优先级"越低。nice 值中的 -20 到 19,中 -20 优先级最高,0 是默认的值,而 19 优先级最低

PR 值表示 Priority 值叫动态优先级,是进程在内核中实际的优先级值,进程优先级的取值范围是通过一个宏定义的,这个宏的名称是 MAX_PRIO,它的值为 140。Linux 实际上实现了 140 个优先级范围,取值范围是从 0-139,这个值越小,优先级越高。而这其中的 0 - 99 是实时进程的值,而 100 - 139 是给用户的。

其中 PR 中的 100 to 139 值部分有这么一个对应 PR = 20 + (-20 to +19),这里的 -20 to +19 便是 nice 值,所以说两个虽然都是优先级,而且有千丝万缕的关系,但是他们的值,他们的作用范围并不相同

VIRT 任务所使用的虚拟内存的总数,其中包含所有的代码,数据,共享库和被换出 swap 空间的页面等所占空间的总数

在上文我们曾经说过 top 是一个前台程序,所以是一个可以交互的

常用交互命令 解释
q 退出程序
l lrix mode的开关 切换显示单核平均负载和CPU平均负载
P 根据CPU使用百分比大小进行排序
M 根据驻留内存大小进行排序
i 忽略闲置和僵死的进程,这是一个开关式命令
k 终止一个进程,系统提示输入 PID 及发送的信号值。一般终止进程用 15 信号,不能正常结束则使用 9 信号。安全模式下该命令被屏蔽。

好好的利用 top 能够很有效的帮助我们观察到系统的瓶颈所在,或者是系统的问题所在。

5.2 ps 工具

ps 也是我们最常用的查看进程的工具之一,我们通过这样的一个命令来了解一下,他能给我带来哪些信息

ps aux

ps axjf

我们来总体了解下会出现哪些信息给我们,这是信息又代表着什么(更多的 keywords 大家可以通过 man ps 了解,man 命令是一个帮助命令,会在下一张详细讲解)

内容 解释
F 进程的标志(process flags),当 flags 值为 1 则表示此子程序只是 fork 但没有执行 exec,为 4 表示此程序使用超级程序员 root 权限
USER 进程的拥有用户
PID 进程的 ID
PPID 其父进程的 PID
SID session 的 ID
TPGID 前台进程组的 ID
%CPU 进程占用的 CPU 百分比
%MEM 占用内存的百分比
NI 进程的 NICE 值
VSZ 进程使用虚拟内存大小
RSS 驻留内存中页的大小
TTY 终端 ID
S or STAT 进程状态
WCHAN 正在等待的进程资源
START 启动进程的时间
TIME 进程消耗CPU的时间
COMMAND 命令的名称和参数

TPGID 栏写着 -1 的都是没有控制终端的进程,也就是守护进程

STAT 表示进程的状态,而进程的状态有很多,如下表所示

状态 解释
R Running 运行中
S interruptible Sleep 等待调用
D Uninterruptible Sleep 不可中断睡眠
T Stoped 暂停或者跟踪状态
X Dead 即将被撤销
Z Zombie 僵尸进程
W Paging 内存交换
N 优先极低的进程
< 优先级高的进程
s 进程的领导者
L 锁定状态
l 多线程状态
+ 前台进程

其中的 D 是不能被中断睡眠的状态,处在这种状态的进程不接受外来的任何signal,所以无法使用 kill 命令杀掉处于 D 状态的进程,无论是 kill,kill -9 还是 kill -15,一般处于这种状态可能是进程 I/O 的时候出问题了。

ps 工具有许多的参数,下面给大家解释部分常用的参数

使用 -l 参数可以显示自己这次登录的 bash 相关的进程信息罗列出来

ps -l

相关来说我们更加常用下面这个命令,他将会罗列出所有的进程信息

ps aux

若是查找其中的某个进程的话,我们还可以配合着 grep 和正则表达式一起使用

ps aux | grep zsh

此外我们在查看时,可以将连同部分的进程呈树状显示出来

ps axjf

当然如果你觉得使用这样的此时没有把你想要的信息放在一起,我们也可以是用这样的命令,来自定义我们所需要的参数显示

ps -afxo user,ppid,pid,pgid,command

这是一个简单而又实用的工具,想要更灵活的使用,想要知道跟更多的参数我们可以使用 man 来获取更多相关的信息

5.3 pstree 工具

通过 pstree 可以很直接的看到相同的进程数量,最主要的还是我们可以看到所有进程的之间的相关性。

pstree

pstree -up

# 参数选择
# -A:各程序树之间以 ASCII 字元来连接;
# -p:同时列出每个 process 的 PID;
# -u:同时列出每个 process 的所属账户名称。

6. 进程的控制

在上一小节中我们使用到 kill 命令,可以帮助我们控制 job 的生死,同业也可以控制系统中所有的进程生死。

# 首先我们使用图形界面打开了 gedit、gvim,用 ps 可以查看到
ps aux

# 使用9这个信号强制结束 gedit 进程
kill -9 1608

# 我们在查找这个进程的时候就找不到了,同时相关的窗口也关闭了
ps aux | grep gedit

7. 总结

本节实际中我们学习了以下内容,任何不清楚的地方欢迎与我们交流:

  • 进程的关系
  • 工作的管理
  • 进程的状态
  • 进程的控制
  • 进程的执行顺序

在信息的查看,对异常进程的处理,都需要我们会灵活的去查看进程相关信息,该章节相关的知识点较多,大家可以先做一个了解,在使用的时候在翻看手册即可。

请务必保证自己能够动手完成整个实验,只看文字很简单,真正操作的时候会遇到各种各样的问题,解决问题的过程才是收获的过程。

results matching ""

    No results matching ""