Linux系列7:进程管理及系统资源查看

0 引言

一个程序被加载到内存当中运行,那么在内存中的与这个程序执行相关的数据就被称为进程(process)。进程是操作系统上非常重要的概念。所有操作系统上跑的数据都是以进程的形态存在。那么系统的进程有哪些状态?不同的状态会如何影响系统的运作?进程之间是否可以互相控管等等的,这都是我们所必须知道的内容。

1 什么是进程

由前面一连几个章节的数据看来,我们一直强调在 Linux 底下所有的命令与你能够进行的动作都与权限有关, 而系统如何判定你的权限呢?当然就是第十四章帐号管理当中提到的 UID/GID 的相关概念,以及文件的属性相关性罗!再进一步来解释,你现在大概知道,在 Linux 系统当中:『触发任何一个事件时,系统都会将他定义成为一个程序,并且给予这个程序一个 ID ,称为 PID,同时依据启发这个程序的使用者与相关属性关系,给予这个 PID 一组有效的权限配置。』 从此以后,这个 PID 能够在系统上面进行的动作,就与这个 PID 的权限有关了!

看这个定义似乎没有什么很奇怪的地方,不过,您得要了解什么叫做『触发事件』才行啊! 我们在什么情况下会触发一个事件?

1.1 进程与程序(process&program)

我们如何产生一个进程呢?其实很简单啦,就是『运行一个程序或命令』就可以触发一个事件而取得一个 PID 罗!我们说过,系统应该是仅认识 binary file 的,那么当我们要让系统工作的时候,当然就是需要启动一个 binary file 罗,那个 binary file 就是程序 (program) 啦!

那我们知道,每个程序都有三组人马的权限,每组人马都具有 r/w/x 的权限,所以:『不同的使用者身份运行这个 program 时,系统给予的权限也都不相同!』举例来说,我们可以利用 touch 来创建一个空的文件,当 root 运行这个 touch 命令时,他取得的是 UID/GID = 0/0 的权限,而当 dmtsai (UID/GID=501/501) 运行这个 touch 时,他的权限就跟 root 不同啦!我们将这个概念绘制成图示来瞧瞧如下:
在这里插入图片描述
如上图所示,程序一般是放置在实体磁碟中,然后透过使用者的运行来触发。触发后会加载到内存中成为一个个体,那就是进程。 为了操作系统可管理这个程序,因此程序有给予运行者的权限/属性等参数,并包括程序所需要的命令码与数据或文件数据等, 最后再给予一个 PID 。系统就是透过这个 PID 来判断该 process 是否具有权限进行工作的!他是很重要的哩!

举个更常见的例子,我们要操作系统的时候,通常是利用连线程序或者直接在主机前面登陆,然后取得我们的 shell 对吧!那么,我们的 shell 是 bash 对吧,这个 bash 在 /bin/bash 对吧,那么同时间的每个人登陆都是运行 /bin/bash 对吧!不过,每个人取得的权限就是不同!也就是说,我们可以这样看:

在这里插入图片描述
也就是说,当我们登陆并运行 bash 时,系统已经给我们一个 PID 了,这个 PID 就是依据登陆者的 UID/GID (/etc/passwd) 来的啦~以上面的图 1.1.2 配合图 1.1.1 来做说明的话,我们知道 /bin/bash 是一个程序 (program),当 dmtsai 登陆后,他取得一个 PID 号码为 2234 的进程,这个程序的 User/Group 都是 dmtsai ,而当这个进程进行其他作业时,例如上面提到的 touch 这个命令时, 那么由这个进程衍生出来的其他程序在一般状态下,也会沿用这个进程的相关权限的!

让我们将程序与进程作个总结:

  • 程序 (program):通常为 binary program ,放置在储存媒体中 (如硬盘、光盘、软盘、磁带等), 为实体文件的型态存在;

  • 进程 (process):程序被触发后,运行者的权限与属性、程序的程序码与所需数据等都会被加载内存中, 操作系统并给予这个内存内的单元一个识别码 (PID),可以说,进程就是一个正在运行中的程序。

1.2 子进程与父进程

在上面的说明里面,我们有提到所谓的『衍生出来的进程』,是什么东西?这样说好了,当我们登陆系统后,会取得一个 bash 的 shell ,然后,我们用这个 bash 提供的界面去运行另一个命令,例如 /usr/bin/passwd 或者是 touch 等等,那些另外运行的命令也会被触发成为 PID。那个后来运行命令才产生的 PID 就是『子进程』了,而在我们原本的 bash 环境下,就称为『父进程』了!借用我们在 十一章 Bash 谈到的 export 所用的图示好了:
在这里插入图片描述
所以你必须要知道,进程彼此之间是有相关性的!以上面的图示来看,连续运行两个 bash 后,第二个 bash 的父进程就是前一个 bash。因为每个进程都有一个 PID ,那某个进程的父进程该如何判断?就透过 Parent PID (PPID) 来判断即可。此外,由十一章的 export 内容我们也探讨过环境变量的继承问题,子进程可以取得父进程的环境变量啦! 让我们来进行底下的练习,以了解什么是子进程/父进程。

例题:
请在目前的 bash 环境下,再触发一次 bash ,并以『 ps -l 』这个命令观察程序相关的输出资讯。
答:
直接运行 bash ,会进入到子程序的环境中,然后输入 ps -l 后,出现:
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 8074 8072 2 76 0 - 1287 wait pts/1 00:00:00 bash
0 S 0 8102 8074 4 76 0 - 1287 wait pts/1 00:00:00 bash
4 R 0 8118 8102 0 78 0 - 1101 - pts/1 00:00:00 ps
有看到那个 PID 与 PPID 吗?第一个 bash 的 PID 与第二个 bash 的 PPID 都是 8074 啊, 因为第二个 bash 是来自於第一个所产生的嘛!另外,每部主机的进程启动状态都不一样, 所以在你的系统上面看到的 PID 与我这里的显示一定不同!那是正常的!详细的 ps 命令我们会在本章稍后介绍, 这里你只要知道 ps -l 可以查阅到相关的程序资讯即可。

很多朋友常常会发现:『咦!明明我将有问题的进程关闭了,怎么过一阵子他又自动的产生? 而且新产生的那个程序的 PID 与原先的还不一样,这是怎么回事呢?』不要怀疑,如果不是 crontab 工作排程的影响,肯定有一支父进程存在,所以你杀掉子程序后, 父进程就会主动再生一支!那怎么办?正所谓这:『擒贼先擒王』,找出那支父进程,然后将他删除就对啦!

1.3 fork and exec:程序呼叫的流程

其实子进程与父进程之间的关系还挺复杂的,最大的复杂点在於进程互相之间的呼叫。在 Linux 的进程呼叫通常称为 fork-and-exec 的流程 (注1)!进程都会借由父进程以复制 (fork) 的方式产生一个一模一样的子进程, 然后被复制出来的子进程再以 exec 的方式来运行实际要进行的程序,最终就成为一个子进程的存在。 整个流程有点像底下这张图:
在这里插入图片描述
(1)系统先以 fork 的方式复制一个与父进程相同的缓存程序,这个进程与父进程唯一的差别就是 PID 不同! 但是这个缓存进程还会多一个 PPID 的参数,PPID 如前所述,就是父进程的进程识别码啦!然后
(2)缓存进程开始以 exec 的方式加载实际要运行的程序,以上述图示来讲,新的程序名称为 qqq ,最终子进程的程序码就会变成 qqq 了!

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

如果就我们之前学到的一些命令数据来看,其实我们下达的命令都很简单,包括用 ls 显示文件啊、用 touch 创建文件啊、rm/mkdir/cp/mv 等命令管理文件啊、chmod/chown/passwd 等等的命令来管理权限等等的,不过, 这些命令都是运行完就结束了。也就是说,该项命令被触发后所产生的 PID 很快就会终止呢! 那有没有一直在运行的进程啊?当然有啊!而且多的是呢!

举个简单的例子来说好了,我们知道系统每分钟都会去扫瞄 /etc/crontab 以及相关的配置档, 来进行工作排程吧?那么那个工作排程是谁负责的?是 crond 这个程序所管理的,我们将他启动在背景当中一直持续不断的运行, 套句以前 DOS 年代常常说的一句话,那就是『常驻在内存当中的进程』啦!

常驻在内存当中的进程通常都是负责一些系统所提供的功能以服务使用者各项任务,因此这些常驻进程就会被我们称为:服务 (daemon)。系统的服务非常的多, 不过主要大致分成系统本身所需要的服务,例如刚刚提到的 crond 及 atd ,还有 syslog 等等的。还有一些则是负责网络连线的服务,例如 Apache, named, postfix, vsftpd… 等等的。这些网络服务比较有趣的地方,在於这些程序被运行后,他会启动一个可以负责网络监听的端口 (port) ,以提供外部用户端 (client) 的连线要求。

Tips:
以crontab来说,他的主要执行程序名称应该是cron或at才对,为啥要加上个d在后面?而成为crond,atd呢?就是因为Linux希望我们可以简单的判断该进程是否为daemon,所以,一般daemon类型的程序都会加上d在文件名后,包括服务器篇我们看到的httpd,vsftpd,sshd等等都是这样的。

1.5 Linux的多人多任务环境

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

多人环境:
Linux 最棒的地方就在於他的多人多任务环境了!那么什么是『多人多任务』?在 Linux 系统上面具有多种不同的帐号, 每种帐号都有都有其特殊的权限,只有一个人具有至高无上的权力,那就是 root (系统管理员)。除了 root 之外,其他人都必须要受一些限制的!而每个人进入 Linux 的环境配置都可以随著每个人的喜好来配置 (还记得我们在第十一章 BASH 提过的 ~/.bashrc 吧?对了!就是那个光!)!现在知道为什么了吧?因为每个人登陆后取得的 shell 的 PID 不同嘛!

多任务行为:
我们在第零章谈到 CPU 的速度,目前的 CPU 速度可高达几个 GHz。 这代表 CPU 每秒钟可以运行 1 0 9 10^9 这么多次命令。我们的 Linux 可以让 CPU 在各个工作间进行切换, 也就是说,其实每个工作都仅占去 CPU 的几个命令次数,所以 CPU 每秒就能够在各个程序之间进行切换啦! 谁叫 CPU 可以在一秒钟进行这么多次的命令运行。

CPU 切换程序的工作,与这些工作进入到 CPU 运行的排程 (CPU 排程,非 crontab 排程) 会影响到系统的整体效能! 目前 Linux 使用的多工切换行为是非常棒的一个机制,几乎可以将 PC 的性能整个压榨出来! 由于效能非常好,因此当多人同时登陆系统时,其实会感受到整部主机好像就为了你存在一般! 这就是多人多工的环境啦!(注2)

多重登陆环境的七个基本终端窗口:
在 Linux 当中,默认提供了六个文字界面登陆窗口,以及一个图形界面,你可以使用 [Alt]+[F1]…[F7] 来切换不同的终端机界面,而且每个终端机界面的登陆者还可以不同人! 很炫吧!这个东西可就很有用啦!尤其是在某个程序死掉的时候!

其实,这也是多任务环境下所产生的一个情况啦!我们的 Linux 默认会启动六个终端机登陆环境的程序,所以我们就会有六个终端机介面。 您也可以减少啊!就是减少启动的终端机程序就好了。详细的数据可以先查阅 /etc/inittab 这个文件,未来我们在启动管理流程 (第二十章) 会再仔细的介绍的!

特殊的程序管理行为:
以前的鸟哥笨笨的,总是以为使用 Windows 98 就可以啦!后来,因为工作的关系,需要使用 Unix 系统,想说我只要在工作机前面就好,才不要跑来跑去的到 Unix 工作站前面去呢!所以就使用 Windows 连到我的 Unix 工作站工作!好死不死,我一个程序跑下来要 2~3 天,唉~偏偏常常到了第 2.5 天的时候, Windows 98 就给他挂点去!当初真的是给他怕死了~

后来因为换了新计算机,用了随机版的 Windows 2000 ,呵呵,这东西真不错 (指对单人而言) ,在死机的时候, 他可以仅将错误的程序踢掉,而不干扰其他的程序进行,呵呵! 从此以后,就不用担心会死机连连罗!不过,2000 毕竟还不够好,因为有的时候还是会死当!

那么 Linux 会有这样的问题吗?老实说, Linux 几乎可以说绝对不会死机的!因为他可以在任何时候, 将某个被困住的程序杀掉,然后再重新运行该程序而不用重新启动!够炫吧!那么如果我在 Linux 下以文字界面登陆,在萤幕当中显示错误信息后就挂了~动都不能动,该如何是好!? 这个时候那默认的七个窗口就帮上忙啦!你可以随意的再按 [Alt]+[F1]…[F7] 来切换到其他的终端机界面,然后以 ps -aux 找出刚刚的错误程序,然后给他 kill 一下,哈哈,回到刚刚的终端机界面!恩~棒!又回复正常罗!

为什么可以这样做呢?我们刚刚不是提过吗?每个程序之间可能是独立的,也可能有相依性, 只要到独立的程序当中,删除有问题的那个程序,当然他就可以被系统移除掉啦!_

bash 环境下的工作管理 (job control)
我们在上一个小节有提到所谓的『父进程、子进程』的关系,那我们登陆 bash 之后, 就是取得一个名为 bash 的 PID 了,而在这个环境底下所运行的其他命令, 就几乎都是所谓的子程序了。那么,在这个单一的 bash 介面下,我可不可以进行多个工作啊? 当然可以啦!可以『同时』进行喔!举例来说,我可以这样做:

[root@www ~]# cp file1 file2 &

在这一串命令中,重点在那个 & 的功能,他表示将 file1 这个文件复制为 file2 ,且放置於背景中运行, 也就是说运行这一个命令之后,在这一个终端介面仍然可以做其他的工作!而当这一个命令 (cp file1 file2) 运行完毕之后,系统将会在你的终端介面显示完成的消息!很便利喔!

多人多任务的系统资源分配问题考虑:
多人多工确实有很多的好处,但其实也有管理上的困扰,因为使用者越来越多, 将导致你管理上的困扰哩!另外,由於使用者日盛,当使用者达到一定的人数后, 通常你的机器便需要升级了,因为 CPU 的运算与 RAM 的大小可能就会不敷使用!

举个例子来说,鸟哥之前的网站管理的有点不太好,因为使用了一个很复杂的人数统计程序, 这个程序会一直去取用 MySQL 数据库的数据,偏偏因为流量大,造成 MySQL 很忙碌。 在这样的情况下,当鸟哥要登陆去写网页数据,或者要去使用讨论区的资源时, 哇!慢的很!简直就是『龟速』啊!后来终於将这个程序停止不用了, 以自己写的一个小程序来取代,呵呵!这样才让 CPU 的负载 (loading) 整个降下来~ 用起来顺畅多了! _

2 工作管理

这个工作管理 (job control) 是用在 bash 环境下的,也就是说:『当我们登陆系统取得 bash shell 之后,在单一终端机介面下同时进行多个工作的行为管理 』。举例来说,我们在登陆 bash 后, 想要一边复制文件、一边进行数据搜寻、一边进行编译,还可以一边进行 vi 程序撰写! 当然我们可以重复登陆那六个文字介面的终端机环境中,不过,能不能在一个 bash 内达成? 当然可以啊!就是使用 job control 啦! _

2.1 什么是工作管理

从上面的说明当中,你应该要了解的是:『进行工作管理的行为中, 其实每个工作都是目前 bash 的子程序,亦即彼此之间是有相关性的。 我们无法以 job control 的方式由 tty1 的环境去管理 tty2 的 bash !』 这个概念请你得先创建起来,后续的范例介绍之后,你就会清楚的了解罗!

或许你会觉得很奇怪啊,既然我可以在六个终端介面登陆,那何必使用 job control 呢? 真是脱裤子放屁,多此一举啊!不要忘记了呢,我们可以在 /etc/security/limits.conf (第十四章) 里面配置使用者同时可以登陆的连线数,在这样的情况下,某些使用者可能仅能以一个连线来工作呢! 所以罗,你就得要了解一下这种工作管理的模式了!此外,这个章节内容也会牵涉到很多的数据流重导向,所以,如果忘记的话, 务必回到第十一章 BASH Shell 看一看喔!

由於假设我们只有一个终端介面,因此在可以出现提示字节让你操作的环境就称为前景 (foreground),至於其他工作就可以让你放入背景 (background) 去暂停或运行。 要注意的是,放入背景的工作想要运行时, 他必须不能够与使用者互动。举例来说, vim 绝对不可能在背景里面运行 (running) 的!因为你没有输入数据他就不会跑啊! 而且放入背景的工作是不可以使用 [ctrl]+c 来终止的』!

总之,要进行 bash 的 job control 必须要注意到的限制是:

  • 这些工作所触发的程序必须来自於你 shell 的子程序(只管理自己的 bash);
  • 前景:你可以控制与下达命令的这个环境称为前景的工作 (foreground);
  • 背景:可以自行运行的工作,你无法使用 [ctrl]+c 终止他,可使用 bg/fg 呼叫该工作;
  • 背景中『运行』的程序不能等待 terminal/shell 的输入(input)

接下来让我们实际来管理这些工作吧!

2.2 job control的管理

如前所述,bash 只能够管理自己的工作而不能管理其他 bash 的工作,所以即使你是 root 也不能够将别人的 bash 底下的 job 给他拿过来运行。此外,又分前景与背景,然后在背景里面的工作状态又可以分为『暂停 (stop)』与『运行中 (running)』。那实际进行 job 控制的命令有哪些?底下就来谈谈。

2.2.1 直接将命令丢到背景中『运行』的 &

如同前面提到的,我们在只有一个 bash 的环境下,如果想要同时进行多个工作, 那么可以将某些工作直接丢到背景环境当中,让我们可以继续操作前景的工作!那么如何将工作丢到背景中? 最简单的方法就是利用『 & 』这个玩意儿了!举个简单的例子,我们要将 /etc/ 整个备份成为 /tmp/etc.tar.gz 且不想要等待,那么可以这样做:


[root@www ~]# tar -zpcf /tmp/etc.tar.gz /etc &
[1] 8400  <== [job number] PID 
[root@www ~]# tar: Removing leading `/' from member names 
# 在中括号内的号码为工作号码 (job number),该号码与 bash 的控制有关。
# 后续的 8400 则是这个工作在系统中的 PID。至於后续出现的数据是 tar 运行的数据流,
# 由於我们没有加上数据流重导向,所以会影响画面!不过不会影响前景的操作喔!

仔细的瞧一瞧,我在输入一个命令后,在该命令的最后面加上一个『 & 』代表将该命令丢到背景中, 此时 bash 会给予这个命令一个『工作号码(job number)』,就是那个 [1] 啦!至於后面那个 8400 则是该命令所触发的『 PID 』了! 而且,有趣的是,我们可以继续操作 bash 呢!很不赖吧! 不过,那么丢到背景中的工作什么时候完成?完成的时候会显示什么?如果你输入几个命令后,突然出现这个数据:

[1]+  Done                    tar -zpcf /tmp/etc.tar.gz /etc

就代表 [1] 这个工作已经完成 (Done) ,该工作的命令则是接在后面那一串命令列。 这样了解了吧!另外,这个 & 代表:『将工作丢到背景中去运行』喔! 注意到那个『运行』的字眼!此外,这样的情况最大的好处是: 不怕被 [ctrl]+c 中断的啦! 此外,将工作丢到背景当中要特别注意数据的流向喔!包括上面的信息就有出现错误信息,导致我的前景被影响。 虽然只要按下 [enter] 就会出现提示字节。但如果我将刚刚那个命令改成:

[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc &

情况会怎样?在背景当中运行的命令,如果有 stdout 及 stderr 时,他的数据依旧是输出到萤幕上面的, 所以,我们会无法看到提示字节,当然也就无法完好的掌握前景工作。同时由於是背景工作的 tar , 此时你怎么按下 [ctrl]+c 也无法停止萤幕被搞的花花绿绿的!所以罗,最佳的状况就是利用数据流重导向, 将输出数据传送至某个文件中。举例来说,我可以这样做:

[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc > /tmp/log.txt 2>&1 &
[1] 8429
[root@www ~]# 

命令中的1表示标准输出,&1表示标准输出的引用,2表示标准错误输出。上面命令的意思是将标准输出重定向到文件/tmp/log.txt,将标准错误输出重定向到标准输出的引用。如此一来,标准输出和错误输出都给他传送到 /tmp/log.txt 当中,当然就不会影响到我们前景的作业了。 这样说,您应该可以更清楚数据流重导向的重要性了吧!有关command>file 2>&1 & 命令的详细解释请参考Linux系列8:command>file 2>&1 & 命令详解

Tips:
工作号码 (job number) 只与你这个 bash 环境有关,但是他既然是个命令触发的咚咚,所以当然一定是一个程序, 因此你会观察到有 job number 也搭配一个 PID !

2.2.2 将『目前』的工作丢到背景中『暂停』:[ctrl]-z

想个情况:如果我正在使用 vi ,却发现我有个文件不知道放在哪里,需要到 bash 环境下进行搜寻,此时是否要结束 vi 呢?呵呵!当然不需要啊!只要暂时将 vi 给他丢到背景当中等待即可。 例如以下的案例:

[root@www ~]# vi ~/.bashrc
# 在 vi 的一般模式下,按下 [ctrl]-z 这两个按键
[1]+  Stopped                 vim ~/.bashrc
[root@www ~]#   <==顺利取得了前景的操控权!
[root@www ~]# find / -print
....(输出省略)....
# 此时萤幕会非常的忙碌!因为萤幕上会显示所有的档名。请按下 [ctrl]-z 暂停
[2]+  Stopped                 find / -print

在 vi 的一般模式下,按下 [ctrl] 及 z 这两个按键,萤幕上会出现 [1] ,表示这是第一个工作, 而那个 + 代表最近一个被丢进背景的工作,且目前在背景下默认会被取用的那个工作 (与 fg 这个命令有关 )!而那个 Stopped 则代表目前这个工作的状态。默认的情况下,使用 [ctrl]-z 丢到背景当中的工作都是『暂停』的状态喔!

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

[root@www ~]# jobs [-lrs]
选项与参数:
-l  :除了列出 job number 与命令串之外,同时列出 PID 的号码;
-r  :仅列出正在背景 run 的工作;
-s  :仅列出正在背景当中暂停 (stop) 的工作。

范例一:观察目前的 bash 当中,所有的工作,与对应的 PID
[root@www ~]# jobs -l
[1]- 10314 Stopped                 vim ~/.bashrc
[2]+ 10833 Stopped                 find / -print

如果想要知道目前有多少的工作在背景当中,就用 jobs 这个命令吧!一般来说,直接下达 jobs 即可! 不过,如果你还想要知道该 job number 的 PID 号码,可以加上 -l 这个参数啦! 在输出的资讯当中,例如上表,仔细看到那个 + - 号喔!那个 + 代表默认的取用工作。 所以说:『目前我有两个工作在背景当中,两个工作都是暂停的, 而如果我仅输入 fg 时,那么那个 [2] 会被拿到前景当中来处理』!

其实 + 代表最近被放到背景的工作号码, - 代表最近最后第二个被放置到背景中的工作号码。 而超过最后第三个以后的工作,就不会有 +/- 符号存在了!

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

刚刚提到的都是将工作丢到背景当中去运行的,那么有没有可以将背景工作拿到前景来处理的? 有啊!就是那个 fg (foreground) 啦!举例来说,我们想要将上头范例当中的工作拿出来处理时:

[root@www ~]# fg %jobnumber
选项与参数:
%jobnumber :jobnumber 为工作号码(数字)。注意,那个 % 是可有可无的!

范例一:先以 jobs 观察工作,再将工作取出:
[root@www ~]# jobs
[1]- 10314 Stopped                 vim ~/.bashrc
[2]+ 10833 Stopped                 find / -print
[root@www ~]# fg      <==默认取出那个 + 的工作,亦即 [2]。立即按下[ctrl]-z
[root@www ~]# fg %1   <==直接规定取出的那个工作号码!再按下[ctrl]-z
[root@www ~]# jobs
[1]+  Stopped                 vim ~/.bashrc
[2]-  Stopped                 find / -print

经过 fg 命令就能够将背景工作拿到前景来处理罗!不过比较有趣的是最后一个显示的结果,我们会发现 + 出现在第一个工作后! 怎么会这样啊?这是因为你刚刚利用 fg %1 将第一号工作捉到前景后又放回背景,此时最后一个被放入背景的将变成 vi 那个命令动作, 所以当然 [1] 后面就会出现 + 了!了解乎!另外,如果输入『 fg - 』 则代表将 - 号的那个工作号码拿出来,上面就是 [2]- 那个工作号码啦!

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

我们刚刚提到,那个 [ctrl]-z 可以将目前的工作丢到背景底下去『暂停』, 那么如何让一个工作在背景底下『 Run 』呢?我们可以在底下这个案例当中来测试! 注意喔!底下的测试要进行的快一点!_

范例一:一运行 find / -perm +7000 > /tmp/text.txt 后,立刻丢到背景去暂停!
[root@www ~]# find / -perm +7000 > /tmp/text.txt
# 此时,请立刻按下 [ctrl]-z 暂停!
[3]+  Stopped                 find / -perm +7000 > /tmp/text.txt

范例二:让该工作在背景下进行,并且观察他!!
[root@www ~]# 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 &  <==用 bg%3 的情况!
[1]+  Stopped                 vim ~/.bashrc
[2]   Stopped                 find / -print
[3]-  Running                 find / -perm +7000 > /tmp/text.txt &

看到哪里有差异吗?呼呼!没错!就是那个状态列~以经由 Stopping 变成了 Running 罗! 看到差异点,嘿嘿!命令列最后方多了一个 & 的符号罗! 代表该工作被启动在背景当中了啦!

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

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

[root@www ~]# kill -signal %jobnumber
[root@www ~]# kill -l
选项与参数:
-l  :这个是 L 的小写,列出目前 kill 能够使用的讯号 (signal) 有哪些?
signal :代表给予后面接的那个工作什么样的指示罗!用 man 7 signal 可知:
  -1 :重新读取一次参数的配置档 (类似 reload);
  -2 :代表与由键盘输入 [ctrl]-c 同样的动作;
  -9 :立刻强制删除一个工作;
  -15:以正常的程序方式终止一项工作。与 -9 是不一样的。

范例一:找出目前的 bash 环境下的背景工作,并将该工作『强制删除』。
[root@www ~]# jobs
[1]+  Stopped                 vim ~/.bashrc
[2]   Stopped                 find / -print
[root@www ~]# kill -9 %2; jobs
[1]+  Stopped                 vim ~/.bashrc
[2]   Killed                  find / -print
# 再过几秒你再下达 jobs 一次,就会发现 2 号工作不见了!因为被移除了!

范例:找出目前的 bash 环境下的背景工作,并将该工作『正常终止』掉。
[root@www ~]# jobs
[1]+  Stopped                 vim ~/.bashrc
[root@www ~]# kill -SIGTERM %1
# -SIGTERM 与 -15 是一样的!您可以使用 kill -l 来查阅!

特别留意一下, -9 这个 signal 通常是用在『强制删除一个不正常的工作』时所使用的, -15 则是以正常步骤结束一项工作(15也是默认值),两者之间并不相同呦!举上面的例子来说, 我用 vi 的时候,不是会产生一个 .filename.swp 的文件吗? 那么,当使用 -15 这个 signal 时, vi 会尝试以正常的步骤来结束掉该 vi 的工作, 所以 .filename.swp 会主动的被移除。但若是使用 -9 这个 signal 时,由於该 vi 工作会被强制移除掉,因此, .filename.swp 就会继续存在文件系统当中。这样您应该可以稍微分辨一下了吧?

其实, kill 的妙用是很无穷的啦!他搭配 signal 所详列的资讯 (用 man 7 signal 去查阅相关数据) 可以让您有效的管理工作与进程(Process),此外,那个 killall 也是同样的用法! 至於常用的 signal 您至少需要了解 1, 9, 15 这三个 signal 的意义才好。 此外, signal 除了以数值来表示之外,也可以使用讯号名称喔! 举例来说,上面的范例二就是一个例子啦!至於 signal number 与名称的对应, 呵呵,使用 kill -l 就知道啦(L的小写)!

另外, kill 后面接的数字默认会是 PID ,如果想要管理 bash 的工作控制,就得要加上 %数字了, 这点也得特别留意才行喔!

2.3 离线管理问题:nohup

要注意的是,我们在工作管理当中提到的『背景』指的是在终端机模式下可以避免 [crtl]-c 中断的一个情境, 并不是放到系统的背景去喔!所以,工作管理的背景依旧与终端机有关啦! 在这样的情况下,如果你是以远程连线方式连接到你的 Linux 主机,并且将工作以 & 的方式放到背景去, 请问,在工作尚未结束的情况下你离线了,该工作还会继续进行吗?答案是『否』!不会继续进行,而是会被中断掉。
那怎么办?如果我的工作需要进行一大段时间,我又不能放置在背景底下,那该如何处理呢? 首先,你可以参考前一章的 at 来处理即可!因为 at 是将工作放置到系统背景, 而与终端机无关。如果不想要使用 at 的话,那你也可以尝试使用 nohup 这个命令来处理喔!这个 nohup 可以让你在离线或注销系统后,还能够让工作继续进行。他的语法有点像这样:

[root@www ~]# nohup [命令与参数]   <==在终端机前景中工作
[root@www ~]# nohup [命令与参数] & <==在终端机背景中工作

有够好简单的命令吧!上述命令需要注意的是, nohup 并不支持 bash 内建的命令,因此你的命令必须要是外部命令才行。 我们来尝试玩一下底下的任务吧!


# 1. 先编辑一支会『睡著 500 秒』的程序:
[root@www ~]# vim sleep500.sh
#!/bin/bash
/bin/sleep 500s
/bin/echo "I have slept 500 seconds."

# 2. 丢到背景中去运行,并且立刻注销系统:
[root@www ~]# chmod a+x sleep500.sh
[root@www ~]# nohup ./sleep500.sh &
[1] 5074
[root@www ~]# nohup: appending output to ‘nohup.out’ <==会告知这个信息!
[root@www ~]# exit

如果你再次登陆的话,再使用 pstree 去查阅你的程序,会发现 sleep500.sh 还在运行中喔!并不会被中断掉! 这样了解意思了吗?由於我们的程序最后会输出一个信息,但是 nohup 与终端机其实无关了, 因此这个信息的输出就会被导向『 ~/nohup.out 』,所以你才会看到上述命令中,当你输入 nohup 后, 会出现那个提示信息罗。

如果你想要让在背景的工作在你注销后还能够继续的运行,那么使用 nohup 搭配 & 是不错的运行情境喔! 可以参考看看!

3 进程管理

本章一开始就提到所谓的『进程』的概念,包括进程的触发、子进程与父进程的相关性等等, 此外,还有那个『进程的相依性』以及所谓的『僵尸进程』等等需要说明的呢!为什么进程管理这么重要呢?这是因为:

  • 首先,本章一开始就谈到的,我们在操作系统时的各项工作其实都是经过某个 PID 来达成的 (包括你的 bash 环境), 因此,能不能进行某项工作,就与该进程的权限有关了。
  • 再来,如果您的 Linux 系统是个很忙碌的系统,那么当整个系统资源快要被使用光时, 您是否能够找出最耗系统的那个进程,然后删除该进程,让系统恢复正常呢?
  • 此外,如果由於某个进程写的不好,导致产生一个有问题的进程在内存当中,您又该如何找出他,然后将他移除呢?
  • 如果同时有五六项工作在您的系统当中运行,但其中有一项工作才是最重要的, 该如何让那一项重要的工作被最优先运行呢?

所以罗,一个称职的系统管理员,必须要熟悉进程的管理流程才行,否则当系统发生问题时,还真是很难解决问题呢! 底下我们会先介绍如何观察进程与进程的状态,然后再加以进程控制罗!

3.1 进程查看

既然进程这么重要,那么我们如何查阅系统上面正在运行当中的进程呢?很简单啊! 利用静态的 ps 或者是动态的 top,还能以 pstree 来查阅进程树之间的关系喔!

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


[root@www ~]# ps aux  <==观察系统所有的进程数据
[root@www ~]# ps -lA  <==也是能够观察所有系统的数据
[root@www ~]# ps axjf <==连同部分进程树状态
选项与参数:
-A  :所有的 process 均显示出来,与 -e 具有同样的效用;
-a  :不与 terminal 有关的所有 process ;
-u  :有效使用者 (effective user) 相关的 process ;
x   :通常与 a 这个参数一起使用,可列出较完整资讯。
输出格式规划:
l   :较长、较详细的将该 PID 的的资讯列出;
j   :工作的格式 (jobs format)
-f  :做一个更为完整的输出。

鸟哥个人认为 ps 这个命令的 man page 不是很好查阅,因为很多不同的 Unix 都使用这个 ps 来查阅进程状态, 为了要符合不同版本的需求,所以这个 man page 写的非常的庞大!因此,通常鸟哥都会建议你,直接背两个比较不同的选项, 一个是只能查阅自己 bash 进程的『 ps -l 』一个则是可以查阅所有系统运行的进程『 ps aux 』!注意,你没看错,是『 ps aux 』没有那个减号 (-) !先来看看关於自己 bash 进程状态的观察:

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

范例一:将目前属於您自己这次登陆的 PID 与相关资讯列示出来(只与自己的 bash 有关)
[root@www ~]# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0 13639 13637  0  75   0 -  1287 wait   pts/1    00:00:00 bash
4 R     0 13700 13639  0  77   0 -  1101 -      pts/1    00:00:00 ps

系统整体的进程运行是非常多的,但如果使用 ps -l 则仅列出与你的操作环境 (bash) 有关的进程而已, 亦即最上一级的父进程会是你自己的 bash 而没有延伸到 init 这支进程去!那么 ps -l 秀出来的数据有哪些呢? 我们就来观察看看:

  • F:代表这个进程旗标 (process flags),说明这个进程的总结权限,常见号码有:

    • 若为 4 表示此进程的权限为 root ;
    • 若为 1 则表示此子进程仅进行复制(fork)而没有实际运行(exec)。
  • S:代表这个进程的状态 (STAT),主要的状态有:

    • R (Running):该进程正在运行中;
    • S (Sleep):该进程目前正在睡眠状态(idle),但可以被唤醒(signal)。
    • D :不可被唤醒的睡眠状态,通常这支进程可能在等待 I/O 的情况(ex>列印)
    • T :停止状态(stop),可能是在工作控制(背景暂停)或除错 (traced) 状态;
    • Z (Zombie):僵尸状态,进程已经终止但却无法被移除至内存外。
  • UID/PID/PPID:代表『此进程被该 UID 所拥有/进程的 PID 号码/此进程的父进程PID 号码』

  • C:代表 CPU 使用率,单位为百分比;

  • PRI/NI:Priority/Nice 的缩写,代表此进程被 CPU 所运行的优先顺序,数值越小代表该进程越快被 CPU 运行。详细的 PRI 与 NI 将在下一小节说明。

  • ADDR/SZ/WCHAN:都与内存有关,ADDR 是 kernel function,指出该进程在内存的哪个部分,如果是个 running 的进程,一般就会显示『 - 』 / SZ 代表此进程用掉多少内存 / WCHAN 表示目前进程是否运行中,同样的, 若为 - 表示正在运行中。

  • TTY:登陆者的终端机位置,若为远程登陆则使用动态终端介面 (pts/n);

  • TIME:使用掉的 CPU 时间,注意,是此进程实际花费 CPU 运行的时间,而不是系统时间;

  • CMD:就是 command 的缩写,造成此进程的触发进程之命令为何。

所以你看到的 ps -l 输出信息中,他说明的是:『bash 的进程属於 UID 为 0 的使用者,状态为睡眠 (sleep), 之所以为睡眠因为他触发了 ps (状态为 run) 之故。此进程的 PID 为 13639,优先运行顺序为 75 , 下达 bash 所取得的终端介面为 pts/1 ,运行状态为等待 (wait) 。』这样已经够清楚了吧? 您自己尝试解析一下那么 ps 那一行代表的意义为何呢?

接下来让我们使用 ps 来观察一下系统内所有的进程状态吧!
观察系统所有进程: ps aux


范例二:列出目前所有的正在内存当中的进程:
[root@www ~]# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   2064   616 ?        Ss   Mar11   0:01 init [5]
root         2  0.0  0.0      0     0 ?        S<   Mar11   0:00 [migration/0]
root         3  0.0  0.0      0     0 ?        SN   Mar11   0:00 [ksoftirqd/0]
.....(中间省略).....
root     13639  0.0  0.2   5148  1508 pts/1    Ss   11:44   0:00 -bash
root     14232  0.0  0.1   4452   876 pts/1    R+   15:52   0:00 ps aux
root     18593  0.0  0.0   2240   476 ?        Ss   Mar14   0:00 /usr/sbin/atd

你会发现 ps -l 与 ps aux 显示的项目并不相同!在 ps aux 显示的项目中,各栏位的意义为:

  • USER:该 process 属於那个使用者帐号的?
  • PID :该 process 的进程识别码。
  • %CPU:该 process 使用掉的 CPU 资源百分比;
  • %MEM:该 process 所占用的实体内存百分比;
  • VSZ :该 process 使用掉的虚拟内存量 (Kbytes)
  • RSS :该 process 占用的固定的内存量 (Kbytes)
  • TTY :该 process 是在那个终端机上面运行,若与终端机无关则显示 ?,另外, tty1-tty6 是本机上面的登陆者进程,若为 pts/0 等等的,则表示为由网络连接进主机的进程。
  • STAT:该进程目前的状态,状态显示与 ps -l 的 S 旗标相同 (R/S/T/Z)
  • START:该 process 被触发启动的时间;
  • TIME :该 process 实际使用 CPU 运行的时间。
  • COMMAND:该进程的实际命令为何?

一般来说,ps aux 会依照 PID 的顺序来排序显示,我们还是以 13639 那个 PID 那行来说明!该行的意义为『 root 运行的 bash PID 为 13639,占用了 0.2% 的内存容量百分比,状态为休眠 (S),该进程启动的时间为 11:44 , 且取得的终端机环境为 pts/1 。』与 ps aux 看到的其实是同一个进程啦!这样可以理解吗? 让我们继续使用 ps 来观察一下其他的资讯吧!

范例三:以范例一的显示内容,显示出所有的进程:
[root@www ~]# ps -lA
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0     1     0  0  76   0 -   435 -      ?        00:00:01 init
1 S     0     2     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/0
1 S     0     3     1  0  70  -5 -     0 worker ?        00:00:00 events/0
....(以下省略)....
# 你会发现每个栏位与 ps -l 的输出情况相同,但显示的进程则包括系统所有的进程。

范例四:列出类似进程树的进程显示:
[root@www ~]# ps axjf
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0     1     1     1 ?           -1 Ss       0   0:01 init [5]
.....(中间省略).....
    1  4586  4586  4586 ?           -1 Ss       0   0:00 /usr/sbin/sshd
 4586 13637 13637 13637 ?           -1 Ss       0   0:00  \_ sshd: root@pts/1
13637 13639 13639 13639 pts/1    14266 Ss       0   0:00      \_ -bash
13639 14266 14266 13639 pts/1    14266 R+       0   0:00          \_ ps axjf
.....(后面省略).....

看出来了吧?其实鸟哥在进行一些测试时,都是以网络连线进主机来测试的,所以罗,你会发现其实进程之间是有相关性的啦! 不过,其实还可以使用 pstree 来达成这个进程树喔!**以上面的例子来看,鸟哥是透过 sshd 提供的网络服务取得一个进程, 该进程提供 bash 给我使用,而我透过 bash 再去运行 ps axjf !**这样可以看的懂了吗?其他各栏位的意义请 man ps (虽然真的很难 man 的出来!) 罗!

范例五:找出与 cron 与 syslog 这两个服务有关的 PID 号码?
[root@www ~]# ps aux | egrep '(cron|syslog)'
root   4286  0.0  0.0  1720   572 ?      Ss  Mar11   0:00 syslogd -m 0
root   4661  0.0  0.1  5500  1192 ?      Ss  Mar11   0:00 crond
root  14286  0.0  0.0  4116   592 pts/1  R+  16:15   0:00 egrep (cron|syslog)
# 所以号码是 4286 及 4661 这两个罗!就是这样找的啦!

除此之外,我们必须要知道的是『僵尸 (zombie) 』进程是什么? 通常,造成僵尸进程的成因是因为该进程应该已经运行完毕,或者是因故应该要终止了, 但是该进程的父进程却无法完整的将该进程结束掉,而造成那个进程一直存在内存当中。 如果你发现在某个进程的 CMD 后面还接上 时,就代表该进程是僵尸进程啦,例如:

apache  8683  0.0  0.9 83384 9992 ?   Z  14:33   0:00 /usr/sbin/httpd <defunct>

当系统不稳定的时候就容易造成所谓的僵尸进程,可能是因为进程写的不好啦,或者是使用者的操作习惯不良等等所造成。 如果你发现系统中很多僵尸进程时,记得啊!要找出该进程的父进程,然后好好的做个追踪,好好的进行主机的环境最佳化啊! 看看有什么地方需要改善的,不要只是直接将他 kill 掉而已呢!不然的话,万一他一直产生,那可就麻烦了! @_@

事实上,通常僵尸进程都已经无法控管,而直接是交给 init 这支进程来负责了,偏偏 init 是系统第一支运行的进程, 他是所有进程的父进程!我们无法杀掉该进程的 (杀掉他,系统就死掉了!),所以罗,如果产生僵尸进程, 而系统过一阵子还没有办法透过核心非经常性的特殊处理来将该进程删除时,那你只好透过 reboot 的方式来将该进程抹去了!

3.1.2 top:动态观察进程的变化

相对於 ps 是撷取一个时间点的进程状态, top 则可以持续侦测进程运行的状态!使用方式如下:

[root@www ~]# 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 的功能非常多!可以用的按键也非常的多!可以参考 man top 的内部说明文件! 鸟哥这里仅是列出一些鸟哥自己常用的选项而已。接下来让我们实际观察一下如何使用 top 与 top 的画面吧!


范例一:每两秒钟升级一次 top ,观察整体资讯:
[root@www ~]# top -d 2
top - 17:03:09 up 7 days, 16:16,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:  80 total,   1 running,  79 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.5%us,  0.5%sy,  0.0%ni, 99.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:    742664k total,   681672k used,    60992k free,   125336k buffers
Swap:  1020088k total,       28k used,  1020060k free,   311156k cached
    <==如果加入 k 或 r 时,就会有相关的字样出现在这里喔!
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND     
14398 root      15   0  2188 1012  816 R  0.5  0.1   0:00.05 top
    1 root      15   0  2064  616  528 S  0.0  0.1   0:01.38 init
    2 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 migration/0
    3 root      34  19     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/0

top 也是个挺不错的进程观察工具!但不同於 ps 是静态的结果输出, top 这个进程可以持续的监测整个系统的进程工作状态。 在默认的情况下,每次升级进程资源的时间为 5 秒,不过,可以使用 -d 来进行修改。 top 主要分为两个画面,上面的画面为整个系统的资源使用状态,基本上总共有六行,显示的内容依序是:

  • 第一行(top…):这一行显示的资讯分别为:

    • 目前的时间,亦即是 17:03:09 那个项目;
    • 启动到目前为止所经过的时间,亦即是 up 7days, 16:16 那个项目;
    • 已经登陆系统的使用者人数,亦即是 1 user项目;
    • 系统在 1, 5, 15 分钟的平均工作负载。我们在第十六章谈到的 batch 工作方式为负载小於 0.8 就是这个负载罗!代表的是 1, 5, 15 分钟,系统平均要负责运行几个进程(工作)的意思。 越小代表系统越闲置,若高於 1 得要注意你的系统进程是否太过繁复了!
  • 第二行(Tasks…):显示的是目前进程的总量与个别进程在什么状态(running, sleeping, stopped, zombie)。 比较需要注意的是最后的 zombie 那个数值,如果不是 0 !好好看看到底是那个 process 变成僵尸了吧?

  • 第三行(Cpus…):显示的是 CPU 的整体负载,每个项目可使用 ? 查阅。需要特别注意的是 %wa ,那个项目代表的是 I/O wait, 通常你的系统会变慢都是 I/O 产生的问题比较大!因此这里得要注意这个项目耗用 CPU 的资源喔! 另外,如果是多核心的设备,可以按下数字键『1』来切换成不同 CPU 的负载率。

  • 第四行与第五行:表示目前的实体内存与虚拟内存 (Mem/Swap) 的使用情况。 再次重申,要注意的是 swap 的使用量要尽量的少!如果 swap 被用的很大量,表示系统的实体内存实在不足!

  • 第六行:这个是当在 top 进程当中输入命令时,显示状态的地方。
    至於 top 下半部分的画面,则是每个 process 使用的资源情况。比较需要注意的是:

  • PID :每个 process 的 ID 啦!

  • USER:该 process 所属的使用者;

  • PR :Priority 的简写,程序的优先运行顺序,越小越早被运行;

  • NI :Nice 的简写,与 Priority 有关,也是越小越早被运行;

  • %CPU:CPU 的使用率;

  • %MEM:内存的使用率;

  • TIME+:CPU 使用时间的累加;

top 默认使用 CPU 使用率 (%CPU) 作为排序的重点,如果你想要使用内存使用率排序,则可以按下『M』, 若要回复则按下『P』即可。如果想要离开 top 则按下『 q 』吧!如果你想要将 top 的结果输出成为文件时, 可以这样做:

范例二:将 top 的资讯进行 2 次,然后将结果输出到 /tmp/top.txt
[root@www ~]# top -b -n 2 > /tmp/top.txt
# 这样一来,嘿嘿!就可以将 top 的资讯存到 /tmp/top.txt 文件中了。

这玩意儿很有趣!可以帮助你将某个时段 top 观察到的结果存成文件,可以用在你想要在系统背景底下运行。 由於是背景底下运行,与终端机的萤幕大小无关,因此可以得到全部的进程画面!那如果你想要观察的进程 CPU 与内存使用率都很低,结果老是无法在第一行显示时,该怎办?我们可以仅观察单一进程喔!如下所示:

范例三:我们自己的 bash PID 可由 $$ 变量取得,请使用 top 持续观察该 PID
[root@www ~]# echo $$
13639  <==就是这个数字!他是我们 bash 的 PID
[root@www ~]# top -d 2 -p 13639
top - 17:31:56 up 7 days, 16:45,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:    742664k total,   682540k used,    60124k free,   126548k buffers
Swap:  1020088k total,       28k used,  1020060k free,   311276k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
13639 root      15   0  5148 1508 1220 S  0.0  0.2   0:00.18 bash

看到没!就只会有一支进程给你看!很容易观察吧!好,那么如果我想要在 top 底下进行一些动作呢? 比方说,修改 NI 这个数值呢?可以这样做:

范例四:承上题,上面的 NI 值是 0 ,想要改成 10 的话?
# 在范例三的 top 画面当中直接按下 r 之后,会出现如下的图样!
top - 17:34:24 up 7 days, 16:47,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 99.5%id,  0.0%wa,  0.0%hi,  0.5%si,  0.0%st
Mem:    742664k total,   682540k used,    60124k free,   126636k buffers
Swap:  1020088k total,       28k used,  1020060k free,   311276k cached
PID to renice: 13639  <==按下 r 然后输入这个 PID 号码
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
13639 root      15   0  5148 1508 1220 S  0.0  0.2   0:00.18 bash

在你完成上面的动作后,在状态列会出现如下的资讯:

Renice PID 13639 to value: 10   <==这是 nice 值
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND

接下来你就会看到如下的显示画面!

top - 17:38:58 up 7 days, 16:52,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:    742664k total,   682540k used,    60124k free,   126648k buffers
Swap:  1020088k total,       28k used,  1020060k free,   311276k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
13639 root      26  10  5148 1508 1220 S  0.0  0.2   0:00.18 bash

看到不同处了吧?底线的地方就是修改了之后所产生的效果!一般来说,如果鸟哥想要找出最损耗 CPU 资源的那个进程时,大多使用的就是 top 这支进程啦!然后强制以 CPU 使用资源来排序 (在 top 当中按下 P 即可), 就可以很快的知道啦!

3.1.3 pstree

[root@www ~]# pstree [-A|U] [-up]
选项与参数:
-A  :各进程树之间的连接以 ASCII 字节来连接;
-U  :各进程树之间的连接以万国码的字节来连接。在某些终端介面下可能会有错误;
-p  :并同时列出每个 process 的 PID;
-u  :并同时列出每个 process 的所属帐号名称。

范例一:列出目前系统上面所有的进程树的相关性:
[root@www ~]# pstree -A
init-+-acpid
     |-atd
     |-auditd-+-audispd---{audispd}  <==这行与底下一行为 auditd 分出来的子进程
     |        `-{auditd}
     |-automount---4*[{automount}]   <==默认情况下,相似的进程会以数字显示
....(中间省略)....
     |-sshd---sshd---bash---pstree   <==就是我们命令运行的那个相依性!
....(底下省略)....
# 注意一下,为了节省版面,所以鸟哥已经删去很多进程了!

范例二:承上题,同时秀出 PID 与 users 
[root@www ~]# pstree -Aup
init(1)-+-acpid(4555)
        |-atd(18593)
        |-auditd(4256)-+-audispd(4258)---{audispd}(4261)
        |              `-{auditd}(4257)
        |-automount(4536)-+-{automount}(4537) <==进程相似但 PID 不同!
        |                 |-{automount}(4538)
        |                 |-{automount}(4541)
        |                 `-{automount}(4544)
....(中间省略)....
        |-sshd(4586)---sshd(16903)---bash(16905)---pstree(16967)
....(中间省略)....
        |-xfs(4692,xfs)   <==因为此进程拥有者并非运行 pstree 者!所以列出帐号
....(底下省略)....
# 在括号 () 内的即是 PID 以及该进程的 owner 喔!不过,由於我是使用 
# root 的身份运行此一命令,所以属於 root 的进程就不会显示出来啦!

如果要找进程之间的相关性,这个 pstree 真是好用到不行!直接输入 pstree 可以查到进程相关性,如上表所示,还会使用线段将相关性进程连结起来哩! 一般连结符号可以使用 ASCII 码即可,但有时因为语系问题会主动的以 Unicode 的符号来连结, 但因为可能终端机无法支持该编码,或许会造成乱码问题。因此可以加上 -A 选项来克服此类线段乱码问题。

由 pstree 的输出我们也可以很清楚的知道,所有的进程都是依附在 init 这支进程底下的! 仔细看一下,这支进程的 PID 是一号喔!因为他是由 Linux 核心所主动呼叫的第一支进程!所以 PID 就是一号了。 这也是我们刚刚提到僵尸进程时有提到,为啥发生僵尸进程需要重新启动? 因为 init 要重新启动,而重新启动 init 就是 reboot 罗!

如果还想要知道 PID 与所属使用者,加上 -u 及 -p 两个参数即可。我们前面不是一直提到, 如果子进程挂点或者是老是砍不掉子进程时,该如何找到父进程吗?呵呵!用这个 pstree 就对了!

3.2 进程的管理

进程之间是可以互相控制的!举例来说,你可以关闭、重新启动服务器软件,服务器软件本身是个进程, 你既然可以让她关闭或启动,当然就是可以控制该进程啦!那么进程是如何互相管理的呢?其实是透过给予该进程一个讯号 (signal) 去告知该进程你想要让她作什么!因此这个讯号就很重要啦!

我们也在本章之前的 bash 工作管理当中提到过, 要给予某个已经存在背景中的工作某些动作时,是直接给予一个讯号给该工作号码即可。那么到底有多少 signal 呢? 你可以使用 kill -l (小写的 L ) 或者是 man 7 signal 都可以查询到!主要的讯号代号与名称对应及内容是:
在这里插入图片描述
上面仅是常见的 signal 而已,更多的讯号资讯请自行 man 7 signal 吧!一般来说,你只要记得『1, 9, 15』这三个号码的意义即可。那么我们如何传送一个讯号给某个进程呢?就透过 kill 或 killall 吧!底下分别来看看:

3.3 关於进程的运行顺序

我们知道 Linux 是多人多工的环境,由 top 的输出结果我们也发现, 系统同时间有非常多的进程在运行中,只是绝大部分的进程都在休眠 (sleeping) 状态而已。 想一想,如果所有的进程同时被唤醒,那么 CPU 应该要先处理那个进程呢?也就是说,那个进程被运行的优先序比较高? 这就得要考虑到进程的优先运行序 (Priority) 与 CPU 排程罗!

Tips:
CPU 排程与前一章的例行性工作排程并不一样。 CPU 排程指的是每支进程被 CPU 运行的演算守则, 而例行性工作排程则是将某支进程安排在某个时间再交由系统运行。 CPU 排程与操作系统较具有相关性!

3.3.1 Priority 与 Nice 值

我们知道 CPU 一秒钟可以运行多达数 G 的微命令次数,透过核心的 CPU 排程可以让各进程被 CPU 所切换运行, 因此每个进程在一秒钟内或多或少都会被 CPU 运行部分的命令码。如果进程都是集中在一个伫列中等待 CPU 的运行, 而不具有优先顺序之分,也就是像我们去游乐场玩热门游戏需要排队一样,每个人都是照顺序来! 你玩过一遍后还想再玩 (没有运行完毕),请到后面继续排队等待。情况有点像底下这样:
在这里插入图片描述
上图中假设 pro1, pro2 是紧急的进程, pro3, pro4 是一般的进程,在这样的环境中,由於不具有优先顺序, 唉啊!pro1, pro2 还是得要继续等待而没有优待呢!如果 pro3, pro4 的工作又臭又长!那么紧急的 pro1, pro2 就得要等待个老半天才能够完成!真麻烦啊!所以罗,我们想要将进程分优先顺序啦!如果优先序较高则运行次数可以较多次, 而不需要与较慢优先的进程抢位置!我们可以将进程的优先顺序与 CPU 排程进行如下图的解释:
在这里插入图片描述
如上图所示,具高优先权的 pro1, pro2 可以被取用两次,而较不重要的 pro3, pro4 则运行次数较少。 如此一来 pro1, pro2 就可以较快被完成啦!要注意,上图仅是示意图,并非较优先者一定会被运行两次啦! 为了要达到上述的功能,我们 Linux 给予进程一个所谓的『优先运行序 (priority, PRI)』, 这个 PRI 值越低代表越优先的意思。不过这个 PRI 值是由核心动态调整的, 使用者无法直接调整 PRI 值的。 先来瞧瞧 PRI 曾在哪里出现?

[root@www ~]# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0 18625 18623  2  75   0 -  1514 wait   pts/1    00:00:00 bash
4 R     0 18653 18625  0  77   0 -  1102 -      pts/1    00:00:00 ps

由於 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 值可调整的范围为 -20 ~ 19 ;
  • root 可随意调整自己或他人进程的 Nice 值,且范围为 -20 ~ 19 ;
  • 一般使用者仅可调整自己进程的 Nice 值,且范围仅为 0 ~ 19 (避免一般用户抢占系统资源);
  • 一般使用者仅可将 nice 值越调越高,例如本来 nice 为 5 ,则未来仅能调整到大於 5;

这也就是说,要调整某个进程的优先运行序,就是『调整该进程的 nice 值』啦!那么如何给予某个进程 nice 值呢?有两种方式,分别是:

  • 一开始运行进程就立即给予一个特定的 nice 值:用 nice 命令;
  • 调整某个已经存在的 PID 的 nice 值:用 renice 命令。

3.3.2 nice :新运行的命令即给予新的 nice 值

[root@www ~]# nice [-n 数字] command
选项与参数:
-n  :后面接一个数值,数值的范围 -20 ~ 19。

范例一:用 root 给一个 nice 值为 -5 ,用於运行 vi ,并观察该进程!
[root@www ~]# nice -n -5 vi &
[1] 18676
[root@www ~]# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0 18625 18623  0  75   0 -  1514 wait   pts/1    00:00:00 bash
4 T     0 18676 18625  0  72  -5 -  1242 finish pts/1    00:00:00 vi
4 R     0 18678 18625  0  77   0 -  1101 -      pts/1    00:00:00 ps
# 原本的 bash PRI 为 75  ,所以 vi 默认应为 75。不过由於给予 nice  为 -5 ,
# 因此 vi 的 PRI 降低了!但并非降低到 70 ,因为核心还会动态调整!

[root@www ~]# kill -9 %1 <==测试完毕将 vi 关闭

就如同前面说的, nice 是用来调整进程的运行优先顺序!这里只是一个运行的范例罢了! 通常什么时候要将 nice 值调大呢?举例来说,系统的背景工作中, 某些比较不重要的进程之进行:例如备份工作!由於备份工作相当的耗系统资源, 这个时候就可以将备份的命令之 nice 值调大一些,可以使系统的资源分配的更为公平!

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

[root@www ~]# renice [number] PID
选项与参数:
PID :某个进程的 ID 啊!

范例一:找出自己的 bash PID ,并将该 PID 的 nice 调整到 10
[root@www ~]# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0 18625 18623  0  75   0 -  1514 wait   pts/1    00:00:00 bash
4 R     0 18712 18625  0  77   0 -  1102 -      pts/1    00:00:00 ps

[root@www ~]# renice 10 18625
18625: old priority 0, new priority 10

[root@www ~]# ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0 18625 18623  0  85  10 -  1514 wait   pts/1    00:00:00 bash
4 R     0 18715 18625  0  87  10 -  1102 -      pts/1    00:00:00 ps

如果要调整的是已经存在的某个进程的话,那么就得要使用 renice 了。使用的方法很简单, renice 后面接上数值及 PID 即可。因为后面接的是 PID ,所以你务必要以 ps 或者其他进程观察的命令去找出 PID 才行啊!

由上面这个范例当中我们也看的出来,虽然修改的是 bash 那个进程,但是该进程所触发的 ps 命令当中的 nice 也会继承而为 10 喔!了解了吧!整个 nice 值是可以在父进程 --> 子进程之间传递的呢! 另外,除了 renice 之外,其实那个 top 同样的也是可以调整 nice 值的!

3.4 系统资源的查看

除了系统的进程之外,我们还必须就系统的一些资源进行检查啊!举例来说,我们使用 top 可以看到很多系统的资源对吧!那么,还有没有其他的工具可以查阅的? 当然有啊!底下这些工具命令可以玩一玩!

3.4.1 free :观察内存使用情况

[root@www ~]# free [-b|-k|-m|-g] [-t]
选项与参数:
-b  :直接输入 free 时,显示的单位是 Kbytes,我们可以使用 b(bytes), m(Mbytes)
      k(Kbytes), 及 g(Gbytes) 来显示单位喔!
-t  :在输出的最终结果,显示实体内存与 swap 的总量。

范例一:显示目前系统的内存容量
[root@www ~]# free -m
          total       used    free   shared   buffers    cached
Mem:        725        666      59        0       132       287
-/+ buffers/cache:     245     479
Swap:       996          0     996

仔细看看,我的系统当中有 725MB 左右的实体内存,我的 swap 有 1GB 左右, 那我使用 free -m 以 MBytes 来显示时,就会出现上面的资讯。Mem 那一行显示的是实体内存的量, Swap 则是虚拟内存的量。 total 是总量, used 是已被使用的量, free 则是剩余可用的量。 后面的 shared/buffers/cached 则是在已被使用的量当中,用来作为缓冲及缓存的量。

仔细的看到范例一的输出喔,我们的 Linux 测试用主机是很平凡的,根本没有什么工作, 但是,我的实体内存是几乎被用光光的情况呢!不过,至少有 132MB 用在缓冲记忆 (buffers) 工作, 287MB 则用在缓存 (cached) 工作,也就是说,系统是『很有效率的将所有的内存用光光』, 目的是为了让系统的存取效能加速啦!

很多朋友都会问到这个问题『我的系统明明很轻松,为何内存会被用光光?』现在了了吧? 被用光是正常的!而需要注意的反而是 swap 的量。一般来说, swap 最好不要被使用,尤其 swap 最好不要被使用超过 20% 以上, 如果您发现 swap 的用量超过 20% ,那么,最好还是买实体内存来插吧! 因为, Swap 的效能跟实体内存实在差很多,而系统会使用到 swap , 绝对是因为实体内存不足了才会这样做的!如此,了解吧!

Tips:
Linux 系统为了要加速系统效能,所以会将最常使用到的或者是最近使用到的文件数据缓存 (cache) 下来, 这样未来系统要使用该文件时,就直接由内存中搜寻取出,而不需要重新读取硬盘,速度上面当然就加快了! 因此,实体内存被用光是正常的喔!

3.4.2 uname:查阅系统与核心相关资讯

[root@www ~]# uname [-asrmpi]
选项与参数:
-a  :所有系统相关的资讯,包括底下的数据都会被列出来;
-s  :系统核心名称
-r  :核心的版本
-m  :本系统的硬件名称,例如 i686 或 x86_64 等;
-p  :CPU 的类型,与 -m 类似,只是显示的是 CPU 的类型!
-i  :硬件的平台 (ix86)

范例一:输出系统的基本资讯
[root@www ~]# uname -a
Linux www.vbird.tsai 2.6.18-92.el5 #1 SMP Tue Jun 10 18:49:47 EDT 2008 i686
i686 i386 GNU/Linux

这个命令我们前面使用过很多次了喔!uname 可以列出目前系统的核心版本、 主要硬件平台以及 CPU 类型等等的资讯。以上面范例一的状态来说,我的 Linux 主机使用的核心名称为 Linux,而主机名称为 www.vbird.tsai,核心的版本为 2.6.18-92.el5 ,该核心版本创建的日期为 2008/6/10,适用的硬件平台为 i386 以上等级的硬件平台喔。

3.4.3 观察系统启动时间与工作负载

这个命令很单纯呢!就是显示出目前系统已经启动多久的时间,以及 1, 5, 15 分钟的平均负载就是了。还记得 top 吧?没错啦!这个 uptime 可以显示出 top 画面的最上面一行!

[root@www ~]# uptime
 15:39:13 up 8 days, 14:52,  1 user,  load average: 0.00, 0.00, 0.00
# top 这个命令已经谈过相关资讯,不再聊!

3.4.4 netstat :追踪网络或插槽档

3.4.5 dmesg :分析核心产生的信息

3.4.6 vmstat :侦测系统资源变化

4 特殊文件与进程

4.1 具有 SUID/SGID 权限的命令运行状态

4.2 /proc/* 代表的意义

4.3 查询已开启文件或已运行程序开启之文件

主要内容摘自鸟哥的Linux私房菜第十七章、程序管理与 SELinux 初探

发布了149 篇原创文章 · 获赞 931 · 访问量 181万+

猜你喜欢

转载自blog.csdn.net/liuweiyuxiang/article/details/105585773