前言

  • 当一个程序被载入到内存中运行,那么在内存中的那个程序就被称为进程(process)。进程是操作系统上非常重要的概念, 所有系统上面跑的数据都会以进程的形态存在。
  • 那么系统的进程有哪些状态?不同的状态会如何影响系统的运行? 进程之间是否可以互相控管等等, 这些问题都是由本章“进程管理”来讲解的,我们一起来学习吧。

一、什么是进程(process)

  • 在Linux系统当中,触发任何一个事件时,系统都会将它定义为一个进程,并且给予这个进程一个ID,称为PID,同时依据启动这个进程的使用者与相关属性关系,给予这个PID一组有效的权限设置。
  • 从此,这个 PID能够在系统上面进行的动作,就与其权限有关了。那么什么叫做 “触发事件”?在什么情况下会触发一个事件?同一个事件是否能被触发多次?我们继续往下看,解决这些问题。

1. 程序与进程

1.1 程序与进程的区别

  • 如何产生一个进程呢?其实很简单,“执行一个程序或指令”就可以触发一个进程,而取得一个 PID。系统是只认识二进制文件的,当我们要让系统工作的时候,需要启动一个二进制文件,这个二进制文件就是程序 (program) 。
  • 我们知道,每个程序都有三组人马的权限,每组人马都具有 r/w/x 的权限,所以,当不同的使用者执行这个程序(program)时,系统给予的权限也都不相同。
  • 举例来说,我们可以利用 touch 指令来创建一个空的文件,当 root用户执行这个 touch 指令时,他取得的是 UID/GID = 0/0 的权限,而当 dmtsai 用户(UID/GID=501/501) 执行这个 touch指令 时,他取得的权限就跟 root 用户不同了。
  • 举个更常见的例子,我们要操作系统的时候,通常是利用连线程序或者直接在主机前面登陆,然后取得我们的 shell ,我们的 shell都是 bash ,这个 bash 在 /bin/bash 程序下。那么在同一个时间的每个用户登陆都是执行 /bin/bash 这个程序,不过,每个用户得到的权限不同。我们可以这样看:

  • 也就是说,当我们登陆并执行 bash 时,系统已经给我们分配一个 PID 了,这个 PID 就是依据登陆者的 UID/GID (/etc/passwd) 来分配的。 当 dmtsai 登陆后,他取得一个 PID 号码为 2234 的进程,这个进程的 User/Group 都是 dmtsai ,而当这个进程进行其他动作时,例如上面提到的 touch 这个指令, 那么由这个进程衍生出来的其他进程在一般状态下,也会沿用2234这个进程的相关权限的。
  • 让我们将程序与进程作个总结:
    * 程序 (program):通常为二进制文件 ,放置在储存媒体中 (如硬盘、光盘、软 盘、磁带等), 为实体文件的形态存在;
    * 进程 (process):程序被触发后,执行者的权限与属性、程序的代码与所需数据等都会被载入内存中, 操作系统会给予这个内存中的单元一个识别码 (PID)。可以说,进程就是一个正在运行中的程序。

1.2 子进程与父进程

  • 在上面的说明里面,我们有提到所谓的“衍生出来的进程”。当用户登陆系统后,会取得一个 bash 的 shell ,然后,用户使用这个 bash 提供的接口去执行另一个指令,例如 touch 指令等等。这些另外执行的指令也会被触发成为一个个 PID ,后来执行指令而产生的 PID 就是“子进程”,而在我们原本的 bash 环境下的这个进程,就称为 “父进程”。

  • 以上面的图示来看,连续执行两个 bash 后,第二个 bash 的父进程就是第一个 bash。因为每个进程都有一个 PID ,那某个进程的父进程该如何判断?通过 Parent PID (PPID) 来判断即可。

例题:请在目前的 bash 环境下,再触发一次 bash ,并以“ ps -l ”这个指令观察程序相关的输出信息。

[root@LinEYueLunix01 ~] ps -lF S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   8930   8922  0  80   0 - 29163 do_wai pts/0    00:00:00 bash
0 R     0   8974   8930  0  80   0 - 38309 -      pts/0    00:00:00 ps[root@LinEYueLunix01 ~] bash # 再次触发一次bash[root@LinEYueLunix01 ~] ps -lF S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0   8930   8922  0  80   0 - 29163 do_wai pts/0    00:00:00 bash
4 S     0   8983   8930  1  80   0 - 29215 do_wai pts/0    00:00:00 bash
0 R     0   9013   8983  0  80   0 - 38309 -      pts/0    00:00:00 ps
# 可以发现,第二个bash 进程的PPID与第一个bash 进程的PID相同,说明第二个 bash 的父进程就是第一个 bash。
  • 在第一次执行ps -l 指令时,只显示了两个进程,当再一次触发bash 指令后,执行ps -l 指令,出现了三个进程。我们注意到,第二个bash 进程的PPID与第一个bash 进程的PID相同都是8930,说明第二个 bash 的父进程就是第一个 bash。
  • 另外,每部主机的程序启动状态都不一样, 所以在你的系统上面看到的 PID 与本例显示不同,那是正常的。 详细的 ps 指令我们会在稍后介绍, 这里只要知道 ps -l 可以查阅到相关的进程信息即可。

1.3 进程调用的流程(fork and exec)

  • 其实子进程与父进程之间的关系还挺复杂的,最大的复杂点在于进程互相之间的调用。在 Linux 的进程调用通常称为 fork-and-exec 的流程。
  • 进程都会借由父进程以复制 (fork) 的方式产生一个与父进程一模一样的子进程, 然后被复制出来的子进程再以 exec 的方式来执行实际要进行的程序,最终就成为一个子进程的存在。 如下图:
  • (1)系统先以 fork 的方式复制一个与父进程相同的暂存进程,这个进程与父进程唯一的差别就是 PID 不同! 但是这个暂存进程还会多一个 PPID 的参数,PPID 如前所述,与父程序的PID相同。
  • (2)暂存进程开始以 exec 的方式载入实际要执行的程序,以上述图示来讲,新的进程代码为 qqq ,最终子进程的代码就会变成 qqq 了。

1.4 系统或网络服务:常驻在内存的进程

  • 我们之前下达的简单指令都是执行完就结束了,也就是说,该项指令被触发后所产生的 PID 很快就会终止。 那有没有一直在执行的程序?当然有。
  • 举个简单的例子来说好了,系统每分钟都会去扫瞄 /etc/crontab 以及相关的配置文件, 来进行工作调度。工作调度是 crond 这个程序所管理的,我们将它启动在背景当中一直持续不断的运行,这个crond 指令产生的进程就是 “常驻在内存当中的进程”了。
  • 常驻在内存当中的进程通常都是负责一些系统所提供的功能以服务使用者各项任务,因此这些常驻进程被称为:服务 (daemon)。
  • 系统的服务非常多, 不过主要大致分成系统本身所需要的服务,例如刚刚提到的 crond 及 atd ,还有 rsyslogd 等等。还有一些则是负责网络连线的服务,例如 Apache, named, postfix, vsftpd… 等等,这些指令就不在本文中讲解啦。

2. Linux 的多用户多任务环境

  • 我们现在知道了,其实在 Linux 下面执行一个指令时,系统会将相关的权限、属性、代码与数据等均载入内存, 并给予这个内存单元一个程序识别码 (PID),最终该指令可以进行的动作则与这个 PID 的权限有关。 根据这个说明,我们就可以简单的了解,为什么 Linux 这么多用户,但是每个用户都可以拥有自己的环境了。下面我们来谈谈 Linux 的多用户多任务环境特色。

2.1 多人环境

  • 什么是 “多用户多任务”?在 Linux 系统上具有多种不同的帐号, 每种帐号都有都有其特殊的权限,只有一个账号具有至高无上的权力,那就是 root (系统管理员)。除了 root 之外,其他用户都必须要受一些限制。而每个用户进入 Linux 的环境设置都可以随着个人的喜好来设置 ,是因为每个用户登陆后取得的 shell 进程的 PID 不同。

2.2 多任务行为

  • 我们的 Linux 可以让 CPU 在各个工作间进行切换, 也就是说, 其实每个工作都仅占去 CPU 的几个指令次数,所以 CPU 每秒能够在各个进程之间进行切换。
  • CPU 切换进程的工作,与这些工作进入到 CPU 运行的调度 会影响到系统的整体性能。 目前 Linux 使用的多任务切换行为是非常棒的一个机制,几乎可以将 PC 的性能整个压榨出来。 由于性能非常好,因此当多用户同时登陆系统时,会感受到整部主机好像就为了自己而存在一般。 这就是多用户多任务的环境。

2.3 多重登陆环境的七个基本终端窗口

  • Linux 当中,默认提供了六个文字界面登陆窗口,以及一个图形界面,你可以使用 [Alt] + [F1]…[F7] 来切换不同的终端机界面,而且每个终端机界面的登陆者还可以是不同用户。
  • 其实,这也是多任务环境下所产生的一个情况, Linux 默认会启动六个终端机登陆环境的程序,所以我们就会有六个终端机接口。 我们通过减少启动的终端机程序来减少登录环境就可以了。

2.4 特殊的程序管理行为

  • Linux 几乎可以说绝对不会死机。因为它可以在任何时候, 将某个被困住的进程杀掉,然后再重新执行该程序而不用重新开机。
  • 例如,如果我在 Linux 下以文字界面登陆,在屏幕当中显示错误讯息后就卡住了, 这个时候那默认的七个窗口就帮上忙了,你可以随意的按 [Alt]+[F1]…[F7] 来 切换到其他的终端机界面,然后以 ps -aux 指令找出刚刚的错误进程,然后给它 kill 一下, 回到刚刚的终端机界面就发现恢复正常了.

二、工作管理 (job control)

  • 工作管理 (job control) 是使用在 bash 环境下的,也就是说:“当用户登陆系统取得 bash shell 之后,在单一终端机接口下同时进行多个工作的行为管理 ”。
  • 举例来说,我们在登陆 bash 后, 想要一边复制文件、一边进行数据搜寻、一边进行编译,还可以一边进行 vim 程序撰写(当然我们可以重复登陆进那六个命令行的终端机环境中)。不过,能不能在单一终端机接口下的一个 bash 内完成这些工作呢? 当然可以啊,就是使用 job control 。

1. 什么是工作管理?

  • “ 进行工作管理时, 每个工作都是目前 bash 的子进程,它们彼此之间是有相关性的。 我们无法以 job control 的方式由终端接口1 的环境去管理 终端接口2 环境 的 bash 。” 这个概念得先创建起来,后续的范例介绍之后,你就会清楚的了解工作管理的概念。
  • 由于假设我们只有一个终端接口,因此可以出现提示字符让你操作的环境就称为前景 (foreground),至于其他工作就可以让你放入背景 (background) 去暂停或运行。 要注意的是,放入背景的工作想要运行时, 它必须不能够与用户互动。
  • 举例来说, vim 指令是绝对不可能在背景里面执行的(running) !因为如果没有输入数据 vim 是不会执行任何动作的。而且放入背景的工作是不可以使用 [ctrl]+c 来终止。
  • 总之,要进行 bash 的 job control 必须要注意到的限制是:
    * 这些工作所触发的程序必须来自于你 shell 的子进程(只管理自己的 bash)。
    * 前景:你可以控制与下达指令的这个环境称为前景的工作 (foreground)。
    * 背景:可以自动运行的工作,你无法使用 [ctrl]+c 终止它,但可使用 bg / fg 指令调用该工作。
    * 背景中“执行”的工作不能等待 terminal /shell 的输入(input)。

2. job control 的管理

  • 如前所述,每一个用户的 bash 只能够管理自己的工作而不能管理其他用户的 bash 的工作,所以即使你是 root用户也不能够将别人的 bash 下面的 job 拿过来执行。
  • 此外,job 的环境又分前景与背景,然后在背景里面的job 状态又可以分为“暂停 (stop)”与“运行中 (running)。
    接下来我们谈谈实际进行 job 控制的指令

2.1 直接将指令丢到背景中“执行”的(&)

  • 如果想要同时进行多个工作, 那么可以将某些工作直接丢到背景环境当中,让我们可以继续操作前景的工作。那么如何将工作丢到背景中? 最简单的方法就是利用(&)这个指令。
  • 举个简单的例子,我们要将 /etc/ 整个备份成为 /tmp/etc.tar.gz 且不想要等待,那么可以这样做:

  • 分析:第二行,在中括号 [] 内的号码为工作号码 (job number),该号码与 bash 的控制有关。后续的 10326 则是这个工作在系统中的 PID。至于第三行出现的数据则是 tar 执行完成后的数据流。

  • 由于我们没有加上数据流重导向,所以会影响前景画面,便出现了第三行的数据,不过不会影响前景的操作。

  • 用法:输入一个指令后,在该指令的最后面加上一个(&) 代表将该指令丢到背景中, 此时 bash 会给予这个指令一个 “工作号码(job number)”,就是那个 [1] ,至于后面的10326 则是该指令所触发的“ PID ”了。

  • 那么丢到背景中的工作什么时候完成?完成的时候会显示什么?如果你输入几个指令后,突然出现下面的数据:

  • 这就代表 [1] 这个工作已经完成 (Done) ,该工作执行的指令则是接在后面那一串命令行。

  • 符号(&)代表:“将工作丢到背景中去执行”。 注意到“执行”的字眼!这样的情况最大的好处是: 不怕被 [ctrl] + c 中断

  • 将工作丢到背景当中执行时要特别注意数据流的流向。上面的指令就出现了错误数据流信息,导致前景显示被影响。如果将上面的指令改为下面:

  • 你会发现你的屏幕输出了很多数据,是因为:在背景当中执行的指令,如果有标准输出及标准错误信息时,它的数据依旧是输出到前景屏幕上面的 , 所以,我们将无法看到提示字符,当然也就无法完好的掌握前景正在进行的工作。
  • 同时由于在背景工作的是 tar 指令 , 所以此时你无论怎么按下 [ctrl] + c 也无法停止屏幕被搞的花花绿绿。所以,最佳的方法就是利用数据流重导向, 将输出数据流传送至某个文件中。
  • 举例来说:

  • (>) 符号将背景工作输出的数据流都传送到 /tmp/log.txt 文件当中,就不会影响到我们前景的工作了。 这样说,应该可以更清楚数据流重导向的重要性了吧。

2.2 将“目前”的工作丢到背景中“暂停”:[ctrl] z

  • 如果我正在使用 vim ,却发现我有个文件不知道放在哪里,需要到 bash 环境下进行搜寻,此时是否要结束 vim ?当然不!只要暂时将 vim 工作丢到背景当中等待/暂停即可。例如下面的案例:
[root@study ~]$ vim ~/.bashrc # 在 vim 的一般模式下,按下 [ctrl]-z 这两个按键
[1]+ Stopped vim ~/.bashrc [root@study ~]$                    # 顺利取得了前景的操控权!
[root@study ~]$ find / -print ....(输出省略)....
此时屏幕会非常的忙碌!因为屏幕上会显示所有的文件名。请按下 [ctrl] z 暂停
[2]+ Stopped find / -print[root@study ~]$                    # 再次顺利取得了前景的操控权!
  • 用法:vim 的一般模式下,按下 [ctrl] 及 z 这两个按键,屏幕上会出现 [1] ,表示这是第一个工作, 而那个 “+” 代表最近一个被丢进背景的工作,而且是在目前背景下默认会被取用的那个工作 (与 fg 这个指令有关 )。而 Stopped 则代表目前这个工作的状态。在默认的情况下, 使用 [ctrl] z 丢到背景当中的工作都是“暂停”的状态。

2.3 观察目前的背景工作状态: jobs

  • 如果想要知道目前有多少的工作在背景当中,就用 jobs 这个指令。一般来说,直接下达 jobs 即可。 如果想知道该 job number 的 PID 号码,可以加上 -l 这个参数。
[root@study ~]$ jobs [-lrs]# 选项与参数:
-l :除了列出 job number 与指令串之外,同时列出 PID 的号码;
-r :仅列出正在背景 run 的工作;
-s :仅列出正在背景当中暂停 (stop) 的工作。 # 范例一:观察目前的 bash 当中,所有的工作,与对应的 PID
[root@study ~]$ jobs -l [1]- 14566 Stopped vim ~/.bashrc
[2]+ 14567 Stopped find / -print
  • 仔细看到那个“ + / - ” 号,那个“+” 号代表默认的取用工作。 所以说:“目前有两个工作在背景当中,两个工作都是暂停的, 而如果仅输入 fg 指令时,那么那个 [2]+ 的工作会第一个被拿到前景当中来处理”。
  • 其实(+)号代表最后一个被放到背景的工作号码, (-)号代表最后第二个被放置到背景中的工作号码。 而超过最后第三个以后的工作,就不会有 “ +/- ” 符号存在了。

2.4 将背景工作拿到前景来处理:fg

  • 将背景工作拿到前景来处理的指令使用 fg (foreground),举例来说,我们想要将上头范例当中的工作拿出来处理时:
[root@study ~]$ fg %jobnumber 选项与参数:
%jobnumber :jobnumber 为工作号码(数字)。注意,那个 % 是可有可无的! # 范例一:先以 jobs 观察工作,再将工作取出:
[root@study ~]$ jobs -l [1]- 14566 Stopped vim ~/.bashrc
[2]+ 14567 Stopped find / -print [root@study ~]$ fg  # 默认取出那个 + 的工作,亦即 [2]。立即按下[ctrl]-z [root@study ~]$ fg %1  # 直接指定取出的那个工作号码!再按下[ctrl]-z
[root@study ~]$ jobs -l [1]+ 14566 Stopped vim ~/.bashrc
[2]- 14567 Stopped find / -print
  • 经过 fg 指令就能够将背景工作拿到前景来处理了,不过比较有趣的是最后一个显示的结果, 我们会发现(+)出现在第一个工作后。 这是因为你刚刚利用“ fg %1 ” 将第 [1] 号工作捉到前景后又放回背景,此时最后一个被放入背景的将变成 vim 那个指令动作, 所以当然 [1] 后面就会出现“ + ”了。
  • 另外,如果输入“ fg - ” 则代表将“ - ”号的那个工作号码拿出来,以上面最后为例,就是拿出 [2]- 这个工作号码。

2.5 让工作在背景下的状态变成运行中: bg

  • 如何让一个工作在背景下面直接“ Run ”呢?我们可以在下面这个案例当中来测试。 注意,下面的测试要进行的快一点:
范例一:一执行 find / -perm /7000 > /tmp/text.txt 后,立刻丢到背景去暂停!
[root@study ~]$ find / -perm /7000 > /tmp/text.txt
# 此时,请立刻按下 [ctrl]-z 暂停!
[3]+ Stopped find / -perm /7000 > /tmp/text.txt # 范例二:让该工作在背景下进行,并且观察他!!
[root@study ~]$ jobs ; bg %3 ; jobs [1] Stopped vim ~/.bashrc
[2]- Stopped find / -print
[3]+ Stopped find / -perm /7000 > /tmp/text.txt
[3]+ find / -perm /7000 > /tmp/text.txt &
[1]- Stopped vim ~/.bashrc
[2]+ Stopped find / -print
[3] Running find / -perm /7000 > /tmp/text.txt &
  • 我们可以看到,工作 [3] 以经由 Stopping 变成了 Running 。注意![3] 号命令行最后方多了一个“ & ” 的符号, 代表该工作被启动在背景当中了。

2.6 管理背景当中的工作: kill

  • 刚刚我们可以让一个已经在背景当中的工作继续工作,也可以让该工作以 fg 拿到前景来。 那么,如果想要将该工作直接移除呢?或者是将该工作重新启动呢?这个时候就得需要给予该工作一个讯号 (signal) 。此时, kill 这个指令就派上用场了。

  • 用法如下:

[root@study ~]$ kill -signal %jobnumber
[root@study ~]$ kill -l 选项与参数:
-l :这个是 L 的小写,列出目前 kill 能够使用的讯号 (signal) 有哪些?
signal :代表给给予后面接的那个工作什么样的指示啰!用 man 7 signal 可知:
-1 :重新读取一次参数的配置文件 (类似 reload);
-2 :代表与由键盘输入 [ctrl]-c 同样的动作;
-9 :立刻强制删除一个工作;
-15:以正常的程序方式终止一项工作。与 -9 是不一样的。 # 范例一:找出目前的 bash 环境下的背景工作,并将该工作“强制删除”。
[root@study ~]$ jobs[1]+ Stopped vim ~/.bashrc
[2] Stopped find / -print [root@study ~]$ kill -9 %2 ; jobs [1]+ Stopped vim ~/.bashrc
[2] Killed find / -print
# 再过几秒你再下达 jobs 一次,就会发现 2 号工作不见了!因为被移除了! # 范例二:找出目前的 bash 环境下的背景工作,并将该工作“正常终止”掉。
[root@study ~]$ jobs [1]+ Stopped vim ~/.bashrc [root@study ~]$ kill -15 %1
# -SIGTERM 与 -15 是一样的!您可以使用 kill -l 来查阅!
# 不过在这个案例中, vim 的工作无法被结束喔!因为他无法通过 kill 正常终止的意思!
  • 特别留意一下, -9 这个 signal 通常是用在“强制删除一个不正常的工作”时所使用的, -15 则 是以正常步骤结束一项工作(15也是默认值),两者之间并不相同。通常使用 -9 是因为某些进程你真的不知道怎么通过正常手段去终止它,这才用到 -9。

  • 另外, kill 后面接的数字默认会是 PID ,如果想要管理 bash 的工作控制,就得要加上 “ %数字 ” 了, 这点也得特别留意。signal 除了以数值来表示之外,也可以使用讯号名称表示。

  • 关于 kill指令,我们在后面还会详细介绍。

3. 离线管理问题

  • 要注意的是,我们在工作管理当中提到的“背景”指的是在终端机模式下可以避免 [crtl] c 中断 的一个情境, 你可以说那个是 bash 的背景,并不是放到系统的背景中!所以,工作管理的背景依旧与终端机有关。
  • 在这样的情况下,如果你是以远端连线方式连接到你的 Linux 主机,并且将工作以(&)的方式放到背景去, 请问,在工作尚未结束的情况下你离线了,该工作还会继续进行吗?答案是“否”。不会继续进行,而是会被中断掉。
  • 如果我的工作需要进行一大段时间,又不能放置在背景下面,那该如何处理? 你可以尝试使用 nohup 这个指令来处理,这个 nohup 可以让你在离线或登出系统后,还能够让工作继续进行。
  • 用法如下:
[root@study ~]$ nohup [指令与参数]   # 在终端机前景中工作
[root@study ~]$ nohup [指令与参数]   # 在终端机背景中工作
  • 上述指令需要注意的是, nohup 并不支持 bash 内置的指令,因此你的指令必须要是外部指令才行。
  • 如果想要让在背景的工作在你登出后还能够继续的执行,那么使用 nohup 搭配 “&” 是不错的运行情境, 可以参考看看。

三、进程管理

  • 为什么程序管理这么重要呢?
  • 我们在操作系统时的各项工作其实都是经过某个 PID 来达成的 (包括你的 bash 环境),因此,能不能进行某项工作,就与该进程的权限有关了。
    • 当整个系统资源快要被使用光时, 您是否能够找出最耗系统的那个进程,然后删除该进程,让系统恢复正常呢?
    • 如果由于某个程序写的不好,导致产生一个有问题的进程在内存当中,您又该如何找出他,然后将他移除?
    • 如果同时有五六项工作在您的系统当中运行,但其中有一项工作才是最重要的, 该如何 让那一项重要的工作被最优先执行?
  • 所以,一个称职的系统管理员,必须要熟悉进程的管理流程才行,否则当系统发生问题时,真的很难解决问题 。下面我们会先介绍如何观察进程与程序的状态,然后再加以进程控制。

1. 程序的观察

  • 我们如何查阅系统上面正在运行当中的程序呢?很简单,利用静态的 ps指令 或者是动态的 top指令,还能以 pstree 指令来查阅进程树之间的关系。

1.1 ps :将某个时间点的程序运行情况撷取下来

  • 用法如下:
[root@study ~]$ ps aux    # 观察系统所有的程序数据
[root@study ~]$ ps -lA    # 也是能够观察所有系统的数据
[root@study ~]$ ps axjf   # 连同部分程序树状态 选项与参数:
-A :所有的 process 均显示出来,与 -e 具有同样的效用;
-a :不与 terminal 有关的所有 process ;
-u :有效使用者 (effective user) 相关的 process ;
-x :通常与 a 这个参数一起使用,可列出较完整信息。 输出格式规划:
-l :较长、较详细的将该 PID 的的信息列出;
-j :工作的格式 (jobs format)
-f :做一个更为完整的输出。
  • 建议直接背两个比较不同的选项, 一个是只能查阅自己 bash 进程的“ ps -l ”;一个则是可以查阅所有系统运行的进程“ ps aux ”。注意,你没看错,是“ ps aux ”,没有那个减号 (-)。

1.1.1 仅观察自己的 bash 相关程序: ps -l

  • 用法如下:
范例一:将目前属于您自己这次登陆的 PID 与相关信息列示出来(只与自己的 bash 有关)
[root@study ~]$ ps -l F S UID PID  PPID  C PRI NI ADDR SZ    WCHAN  TTY   TIME     CMD
4 S 0   14830   13970 0 80  0   -   52686 poll_s pts/0 00:00:00 sudo
4 S 0   14835   14830 0 80  0   -   50511 wait   pts/0 00:00:00 su
4 S 0   14836   14835 0 80  0   -   29035 wait   pts/0 00:00:00 bash
0 R 0   15011   14836 0 80  0   -   30319 -      pts/0 00:00:00 ps
# 还记得鸟哥说过,非必要不要使用 root 直接登陆吧?从这个 ps -l 的分析,你也可以发现
# 鸟哥其实是使用 sudo 才转成 root 的身份。否则连测试机,鸟哥都是使用一般帐号登陆的!
  • 系统整体的进程运行是非常多的,但如果使用’ ps -l '则仅列出与你的操作环境 (bash) 有关的进程而已, 即最上层的父进程会是你自己的 bash 而没有延伸到 systemd (后续会讲解) 这支进程。 看看第一行各个字段代表什么含义:

  • 所以你看到的’ ps -l '输出信息中,说明的是:“bash 的进程属于 UID 为 0 的使用者,状态为睡眠 (sleep), 之所以为睡眠因为他触发了 ps指令 (状态为 run) 之故。此程序的 PID 为 14836,优先执行顺序为 80 , 下达 bash 所取得的终端接口为 pts/0 ,运行状态为等待(wait)。

1.1.2 观察系统所有程序: ps aux

  • 用法如下:
范例二:列出目前所有的正在内存当中的程序:
[root@study ~]$ ps aux USER PID   %CPU %MEM VSZ    RSS  TTY   STAT START TIME COMMAND
root 1     0.0  0.2  60636  7948 ?     Ss   Aug04 0:01 /usr/lib/systemd/systemd ...
root 2     0.0  0.0  0      0    ?     S    Aug04 0:00 [kthreadd]
.....(中间省略).....
root 14830 0.0  0.1  210744 3988 pts/0 S    Aug04 0:00 sudo su -
root 14835 0.0  0.1  202044 2996 pts/0 S    Aug04 0:00 su -
root 14836 0.0  0.1  116140 2960 pts/0 S    Aug04 0:00 -bash
.....(中间省略).....
root 18459  0.0  0.0 123372 1380 pts/0 R+   00:25 0:00  ps aux
  • 你会发现’ ps -l ‘与’ ps aux '显示的项目并不相同。 在‘’ ps aux '指令显示的项目中,各字段的意义为:
  • 一般来说,'ps aux '会依照 PID 的顺序来排序显示,我们还是以 14836 那个 PID 那行来说明。 该行的意义为 “ root 用户执行的 bash PID 为 14836,占用了 0.1% 的内存容量百分比,状态为休眠 (S),该进程启动的时间为 8 月 4 号,因此启动太久了, 所以没有列出实际的时间点。且取得的终端机环境为 pts/0 。” 与’ ps -l '指令看到的其实是同一个进程。

1.1.3 ps 指令的其他选项

  • 用法如下:

  • 除此之外,我们必须要知道的是“僵尸 (zombie) ”进程是什么? 通常,造成僵尸进程是因为某进程应该已经执行完毕,或者是因故应该要终止了, 但是该进程的父进程却无法完整的将该进程结束掉,从而造成该进程一直存在于内存中。 如果你发现在某个进程的 CMD 字段后面还接上 时,就代表该进程是僵尸进程。
  • 如果你发现系统中有僵尸进程时,记得要找出该进程的父进程,然后做个追踪,进行主机的环境最优化,看看有什么地方需要改善,不要只是直接将该僵尸进程 kill 掉而已。不然的话,万一它一直产生,可就麻烦了。
  • 事实上,通常僵尸进程都已经无法控管,而是应该直接交给 systemd 这支进程来负责了。偏偏 systemd 进程是系统第一支执行的程序, 他是所有进程的父进程。我们是无法杀掉systemd 进程的 (杀掉他,系统就死掉了)。所以,如果产生僵尸进程, 而系统过一阵子还没有办法通过核心非经常性的特殊处理来删除该僵尸进程时,那只能通过 reboot 的方式来将该进程抹去了。

1.2 top:动态观察程序的变化

  • 相对于 ps 是撷取一个时间点的程序状态, top 指令则可以持续侦测程序运行的状态。使用方式如下:
[root@study ~]$ top [-d 数字] | top [-bnp] 选项与参数:
-d :后面可以接秒数,就是整个程序画面更新的秒数。默认是 5 秒;
-b :以批次的方式执行 top ,还有更多的参数可以使用。 通常会搭配数据流重导向来将批次的结果输出成为文件。
-n :与 -b 搭配,意义是,需要进行几次 top 的输出结果。
-p :指定某些个 PID 来进行观察监测而已。 在 top 执行过程当中可以使用的按键指令:
? :显示在 top 当中可以输入的按键指令;
P :以 CPU 的使用资源排序显示;
M :以 Memory 的使用资源排序显示;
N :以 PID 来排序喔!
T :由该 Process 使用的 CPU 时间累积 (TIME+) 排序。
k :给予某个 PID 一个讯号 (signal)
r :给予某个 PID 重新制订一个 nice 值。
q :离开 top 软件的按键。
  • 接下来让我们实际观察一下如何使用 top 与 top 的画面。

  • 不同于 ps 指令是静态的结果输出, top 这个进程可以持续的监测整个系统的进程工作状态。 在默认的情况下,每次更新程序资源的时间为 5 秒,不过,可以使用 -d 选项来进行修改。
  • 以上图为例,top 指令输出主要分为两个画面,上面的画面为整个系统的资源使用状态,基本上总共有六行,显示的内容依序是:


  • 至于 top 下半部分的画面,则是每个 process 使用的资源情况。比较需要注意的是:

  • top 默认使用 CPU 使用率 (%CPU) 作为排序的依据,如果你想要依据内存使用率排序,则可以按下“M”键, 如果想要离开 top 动态界面则按下“ q ”键。
  • 如果你想要将 top 的结果输出成为文件时,可以这样做:
# 范例二:将 top 的输出信息执行 2 次,然后将结果输出到 /tmp/top.txt
[root@study ~]$ top -b -n 2 > /tmp/top.txt
# 这样一来,就可以将 top 的输出信息存到 /tmp/top.txt 文件中了。
  • 那如果你想要观察的进程 CPU 与内存使用率都很低,结果老是无法在第一行显示时,该怎办?我们可以仅观察单一程序。如下:

  • 那么如果我想要在 top 的画面下进行一些动作,比方说,修改 NI 这个数值呢?可以这样做:

  • 输入“r” 键后,在原来空白的第6行会出现上图的 ’ PID to renice [default pid = 14836] ’ 信息,接着在该行输入想要更改NI值的进程的 PID 14836。
  • 在你完成上面的动作后,在第6行状态列会出现:’ Renice PID 29671 to value ’ 提示信息,如下:

  • 然后接着在value 后面输入你想要更改的NI 值,比如说 10, 接下来你就会看到如下的显示画面:

  • 最后一行就是修改了之后所产生的效果,NI值变成了10。 一般来说,如果想要找出损耗 CPU 资源最大的那个进程时,大多使用的就是 top 指令了,然后强制以 CPU 使用资源来排序 (在 top 当中按下 P 即可),便可以很快得到。

1.3 pstree :以树状显示所有进程

  • 用法如下:
[root@study ~]$ pstree [-A|U] [-up]
选项与参数:
-A :各程序树之间的连接以 ASCII 字符来连接;
-U :各程序树之间的连接以万国码的字符来连接。在某些终端接口下可能会有错误;
-p :并同时列出每个 process 的 PID;
-u :并同时列出每个 process 的所属帐号名称。 范例一:列出目前系统上面所有的程序树的相关性:
[root@study ~]$ pstree -A systemd-+-ModemManager---2*[{ModemManager}] # 这行是 ModenManager 与其子进程。|-NetworkManager---3*[{NetworkManager}]  # 前面有数字,代表子进程的数量!
....(中间省略).... |-sshd---sshd---sshd---bash---bash---sudo---su---bash---pstree # 我们指令执行的相依性。
....(下面省略)....
# 注意一下,为了节省版面,所以已经删去很多进程了范例二:承上题,同时秀出 PID 与 users
[root@study ~]$ pstree -Aup systemd(1)-+-ModemManager(745)-+-{ModemManager}(785) | `-{ModemManager}(790) |-NetworkManager(870)-+-{NetworkManager}(907) |                                               |-{NetworkManager}(911) | `-{NetworkManager}(914)
....(中间省略).... |-sshd(1326)---sshd(13923)---sshd(13927,dmtsai)---bash(13928)---bash(13970)---
....(下面省略)....
# 在括号 () 内的即是进程的 PID 以及该进程的 owner 。一般来说,如果该进程的拥有者与父进程相同,
# 就不会列出,但是如果与父进程不一样,那就会列出该程序的拥有者!看上面 13927 的拥有者就转变成 dmtsai 了。
  • 直接输入 pstree 指令可以查到进程相关性,如上表所示,还会使用线段将相关性程序链接起来。
  • 由 pstree 的输出我们也可以很清楚的知道,所有的进程都是依附在 systemd 这支进程下面的。 仔细看一下,这支进程的 PID 是 1号,因为他是由 Linux 核心所主动调用的第一支进程,所以 PID 就是1 号了。 这也是我们刚刚提到僵尸进程,为啥产生僵尸进程后需要重新开机? 因为 systemd 进程要重新启动,而重新启动 systemd 就是 reboot重启了。
  • 如果还想要知道 PID 与所属使用者,加上 -u 及 -p 两个参数即可。我们前面不是一直提到, 如果子程序挂点或者是老是杀不掉子进程时,该如何找到其父进程吗?用这个’ pstree -u -p’ 指令就可以了。

2. 进程的管理

  • 进程之间是可以互相控制的,举例来说,你可以关闭、重新启动服务器软件,服务器软件本身是个进程, 你既然可以让它关闭或启动,就是可以控制该进程。
  • 那么程序是如何互相管理的?其实是通过给予该进程一个讯号 (signal) 去告知该进程你想要让它执行什么任务。
  • 我们也在本章之前的 bash 工作管理当中提到过, 要给予某个已经存在背景中的工作某些动作时,是直接给予一个讯号给该工作号码即可。那么到底有多少 signal 呢? 可以使用’ kill -l ‘(小写的 L ) 或者是’ man 7 signal '都可以查询到。
  • 主要的讯号代号与名称对应及内容如下:

  • 一般来说,你只要记 得“1, 9, 15”这三个号码的意义即可。那么我们如何传送一个讯号给某个进程呢?就通过 kill 或 killall这两个指令了。

2.1 kill -signal PID

  • kill 指令可以帮我们将一个 signal 传送给某个工作 (%jobnumber) 或者是某个 PID (直接输入数字)。 要再次强调的是: kill 后面直接加数字与加上 %number 的情况是不同的。 因为工作管理中有 [1] 号工作,但是 PID 1 号则是专指“ systemd ”这支进程,所以记得 (%)符号 是专门用在工作管理中的。

例题:以 ps 找出 rsyslogd 这个进程的 PID 后,再使用 kill 传送讯息,使得 rsyslogd 可以重新读取配置文件。

由于需要重新读取配置文件,因此 signal 是 1 号。至于找出 rsyslogd 的 PID 可以是这样做:
> ps aux | grep 'rsyslogd' | grep -v 'grep'| awk '{print $2}' 接下来则是实际使用 kill -1 PID,因此,整串指令会是这样:
> kill -SIGHUP $(ps aux | grep 'rsyslogd' | grep -v 'grep'| awk '{print $2}')如果要确认有没有重新启动 syslog ,可以参考登录文件的内容,使用如下指令查阅:
> tail -5 /var/log/messages
  • 如果你有看到类似 “Aug 5 01:25:02 study rsyslogd: [origin software=“rsyslogd” swVersion=“7.4.7” x-pid=“742” x-info=“http://www.rsyslog.com”] rsyslogd was HUPed” 之类的字样,就是表示 rsyslogd 有重新启动 (restart) 过了。

  • 了解这个用法以后,如果未来你想要将某个的登陆者的连线删除的话,就可以通过使用 pstree -p 找到相关进程, 然后再以 kill -9 将该进程删除,该条连线就会被踢掉了。

2.2 killall -signal 启动指令名称

  • 由于 kill 后面必须要加上 PID (或者是 job number),所以,通常 kill 都会配合 ps, pstree 等指令,因为我们必须要找到相对应的那个进程的 PID 。
  • 有没有可以利用“下达指令的名称”来给予讯号的?举例来说,能不能直接将 rsyslogd 这个进程给予一 个 SIGHUP 的讯号呢?可以的.使用 killall指令即可。
  • 用法如下:

  • 总之,要删除某个进程,我们可以使用进程的 PID 或者是启动该进程的指令名称。而如果要删除某个服务呢?最简单的方法就是利用 killall , 因为他可以将系统当中所有以某个指令名称启动的进程全部删除。

3. 关于程序的执行顺序

  • 思考一下,如果所有的进程同时被唤醒,那么 CPU 应该要先处理那个进程?也就是说,哪个进程被执行的优先级比较高? 这就得要考虑到进程的优先执行序 (Priority) 与 CPU 调度了。

3.1 Priority 与 Nice 值

  • 我们 Linux 给予进程一个所谓的“优先执行序(priority, PRI)”, 这个 PRI 值越低代表越优先的意思。不过这个 PRI 值是由核心动态调整的, 使用者无法直接调整 PRI 值。
  • 由于 PRI 值是核心动态调整的,我们使用者也无权去干涉 PRI 值。那如果想要调整进程的优先执行序,就得要通过调整 Nice 值了,Nice 值就是前面出现过的 NI ,一般来说, PRI 与 NI 的相关性如下:
  • PRI(new) = PRI(old) + nice
  • 不过你要特别留意到,如果原本的 PRI 值是 50 ,并不是我们给予 一个 nice = 5 ,就会让 PRI 值变成 55 。 因为 PRI 值是系统“动态”决定的,所以,虽然Nice 值是可以影响 PRI ,不过, 最终的 PRI 值仍是要经过系统分析后才会决定的。
  • 另外, nice 值是有正负的,而既然 PRI 越小越早被执行, 所以,当 nice 值为负值时,那么该进程就会降低 PRI 值,会较优先被处理。
  • 所以要调整某个进程的优先执行序,就是“调整该进程的 nice 值”。那么如何给予某个进程 nice 值呢?有两种方式,分别是:
    1. 一开始执行程序就立即给予一个特定的 nice 值:用 nice 指令;
    2. 调整某个已经存在的进程的 nice 值:用 renice 指令。

3.2 nice :新执行的指令即给予新的 nice 值

  • 用法如下:

  • 通常什么时候要将 nice 值调大呢?举例来说,系统的背景工作中, 某些比较不重要的进程的进行:例如备份工作。由于备份工作相当的耗系统资源, 这个时候就可以将备份的指令之 nice 值调大一些,可以使系统的资源分配的更为公平。

3.3 renice :已存在进程的 nice 重新调整

  • 用法如下:

  • 如果要调整的是已经存在的某个进程的话,那么就得要使用 renice 了。使用的方法很简单, renice 后面接上数值及 PID 即可。因为后面接的是 PID ,所以你务必要以 ps 或者其他进程观察的指令去找出 PID 才行。
  • 由上面这个范例当中我们也看的出来,虽然修改的是 bash 那个程序,但是该程序所触发的 ps 指令当中的 nice 也会继承而为 -5 ,整个 nice 值是可以在父进程 --> 子进程之间传递的。 另外,除了 renice 之外, 前面提到的 top 指令同样可以调整 nice/NI 值。

四、 重点回顾

  • 程序 (program):通常为二进制文件 ,放置在储存媒体中 (如硬盘、光盘、软 盘、磁带等),为实体文件的型态存在;
  • 进程 (process):程序被触发后,执行者的权限与属性、程序的代码与所需数据等都会被载入内存中, 操作系统并给予这个内存内的单元一个识别码 (PID),可以说,进程就是一个正在运行中的程序。
  • 进程彼此之间是有相关性的,故有父进程与子进程之分。而 Linux 系统所有程序的父进程就是 init 这个 PID 为 1 号的进程。
  • 在 Linux 的进程调用通常称为 fork-and-exec 的流程!进程都会借由父程序以复制 (fork) 的方式产生一个一模一样的子进程, 然后被复制出来的子进程再以 exec 的方式来执行实际要进行的程序,最终就成为一个子程序的存在。
  • 常驻在内存当中的进程通常都是负责一些系统所提供的功能以服务使用者各项任务,因此这些常驻进程就会被我们称为:服务 (daemon)。
  • 在工作管理 (job control) 中,可以出现提示字符让你操作的环境就称为前景 (foreground),至于其他工作就可以让你放入背景 (background) 去暂停或运行。
  • 与 job control 有关的按键与关键字有: & , [ctrl]-z, jobs, fg, bg, kill %n 等。
  • 程序管理的观察指令有: ps, top, pstree 等等。
  • 进程之间是可以互相控制的,传递的讯息 (signal) 主要通过 kill 这个指令在处理。
  • 进程是有优先顺序的,该字段为 Priority,但 PRI 是核心动态调整的,使用者只能使用 nice 值去微调 PRI 。
  • nice 值的调整指令有: nice, renice, top 等指令。

五、总结

  • 这个学期学习了操作系统实践这一门课程,为了加深自己对知识的理解以及方便期末复习,小白博主学习了 《鸟哥的Linux私房菜》 这本书,作者语言幽默风趣,把枯燥的操作系统指令进行了生动地讲解,让我受益匪浅!在此感谢鸟哥大佬的无私的知识分享!
  • 在鸟哥原书中,进程管理这一章节后面还有一些内容,但受限于博主的时间与精力不足,便只整理了实用的部分,若对剩余内容感兴趣的朋友,可以自行阅读原书,相信一定能收获良多。
  • 最后,本文若有错漏以及不足之处,欢迎朋友们在评论区进行批评指正。如果本文对您有所帮助,就给小白博主点个赞吧!
  • 咱们下一篇文章见~~

Linux_进程管理详解《鸟哥的Linux私房菜》学习笔记(极其详细,看完这篇就够了)相关推荐

  1. 鸟哥的linux私房菜运维篇,鸟哥的Linux私房菜学习笔记之SAMBA

    鸟哥的Linux私房菜学习笔记之SAMBA 发布时间:2020-06-24 01:44:50 来源:51CTO 阅读:185 作者:tomshen NFS仅能让Unix/linux之间共享数据,CIF ...

  2. 鸟哥的linux私房菜学习笔记《二十》bash简介

    shell的功能: 提供用户操作系统的一个接口. 系统上合法的shell要写在/etc/shells这个文件,因为系统某些服务在运行过程中会去检查用户能够使用的shells,而这些shell的查询就是 ...

  3. 鸟哥linux群,【鸟哥的linux私房菜-学习笔记】linux的帐号与群组

    linux的帐号与群组 使用者标识符: UID 与 GID ID 与账号的对应就在 /etc/passwd 当中: 计算机只认得ID(即数字),并不能区别账号: 每个登陆的使用者至少都会取得两个 ID ...

  4. 鸟哥的Linux私房菜学习笔记(2)登录与在线求助

    以管理员身份运行VMware Player,点击之前安装好的CentOS 7版本的虚拟机,会出现以下界面:  这是我建立的一般账户,ROOT由于身份比较特殊,所以没有被列出来.  点击 "未 ...

  5. Linux管道命令——《鸟哥的Linux私房菜》笔记

    Linux管道命令--<鸟哥的Linux私房菜>笔记 0 前言 看完书之后,总感觉不记录下来的话,很快就会忘了,然后又需要重新到处翻书找资料,所以还是把内容记录下来,方便以后复习.本文大部 ...

  6. 鸟哥的Linux私房菜学习心得-基础操作

    <鸟哥的Linux私房菜>特别适合新手作为Linux的入门教材,即使没有计算机知识基础也能学明白,鸟哥算是很用心了.半个月来学习了鸟哥主页教程的基础篇,感觉良好,因此特意写下学习的感受,以 ...

  7. 鸟哥的Linux私房菜(服务器)- 架站文件習題解答篇

    架站文件習題解答篇 最近更新日期:2003/09/20 在我們的 Linux 架站文件當中,每個章節或多或少都有些課後練習給大家複習一下!呵呵!那麼各個章節的解答會在這裡提供喔! PART I .架站 ...

  8. 鸟哥的 Linux 私房菜学习总结(超赞!!!)

    我是技术搬运工,好东西当然要和大家分享啦.原文地址 常用操作以及概念 求助 1. --help 指令的基本用法与选项介绍. 2. man man 是 manual 的缩写,将指令的具体信息显示出来. ...

  9. 鸟哥的Linux私房菜读书笔记:Linux磁盘与文件系统管理

    系统管理员很重要的任务之一就是管理好自己的磁盘文件系统, 每个分区不可太大也不能太小, 太大会造成磁盘容量的浪费, 太小则会产生文件无法储存的困扰. 前面谈到的文件权限与属性中, 这些权限与属性分别记 ...

  10. 鸟哥的Linux私房菜 读书笔记

    个人表示,每次看电子档,都会从头开始读,话说会一直读不完.以前会有手抄板的读书笔记,但是不方便携带.现在就开始电子档的读书笔记吧. 1. Kernel 必须管理的事项有: * 系统呼叫接口(syste ...

最新文章

  1. 【错误记录】Android NDK 错误排查记录 ( Could not get version from cmake.dir path ‘xxx\cmake\3.6.4111459‘. )
  2. Slim Span UVA - 1395
  3. 对 SAP UI5 一无所知的新手,从哪些材料开始学习比较好?
  4. 高并发下防止库存超卖解决方案
  5. CentOS系统里如何正确取消或者延长屏幕保护自动锁屏功能(图文详解)
  6. 零基础入门python web 自动化测试_web自动化测试从入门到持续集成
  7. centos mpeg acc 解码器安装
  8. java语言的输入输出_java语言的输入输出
  9. C语言文件的存储和处理实验报告,c语言文件处理实验报告(6页)-原创力文档...
  10. Java之JDBC连接池详解
  11. 《Redis开发与运维》学习第四章
  12. 如何在计算机中快速新建TXT文本文档
  13. 酷播智能缓冲服务器,酷播服务器
  14. linux解密shadow_Linux系统中的/etc/shadow文件超详细内容解析
  15. 关于移动端H5获取微信非静默授权被拦截进入【微信快照页】问题及解决方案
  16. App 启动流程与 Activity 启动流程梳理
  17. 数据结构与算法综合实验——队列实现停车场管理系统
  18. 计算机必学知识,基础电脑知识:计算机操作常识入门必学
  19. 将knif4j快速集成到springboot项目中
  20. 【FGF 2】重组人碱性成纤维细胞生长因子新手说明书

热门文章

  1. mac下统计代码行数方法
  2. c语言计算机那类教,C语言教学中的兴趣驱动
  3. 完整电商项目--(八)商品订单模块(1):订单结算与 mysql事务
  4. 【前端17_JS】ES 6:Let 、Const、对象冻结、解构赋值、暂时性死区 TDZ、惰性求值、模板字符串
  5. java程序制作成可执行.exe文件
  6. android so 签名校验,Android-NDK-之so文件签名校验
  7. 【JavaScript】时间与时间戳相互转换
  8. springboot+Rabit实战三:(springboot+rabbit 项目搭建)
  9. Kindle系列(二)免费电子书籍
  10. Android 录制手机内部声音(screen recorder)framework层问题分析