一 、进程的概念和分类
1.进程的概念
 Linux是一个多用户多任务的操作系统。多用户是指多个用户可以在同一时间使用同一个linux系统;多任务是指在Linux下可以同时执行多个任务,更详细的说,linux采用了分时管理的方法,所有的任务都放在一个队列中,操作系统根据每个任务的优先级为每个任务分配合适的时间片,每个时间片很短,用户根本感觉不到是多个任务在运行,从而使所有的任务共同分享系统资源,因此linux可以在一个任务还未执行完时,暂时挂起此任务,又去执行另一个任务,过一段时间以后再回来处理这个任务,直到这个任务完成,才从任务队列中去除。这就是多任务的概念。
上面说的是单CPU多任务操作系统的情形,在这种环境下,虽然系统可以运行多个任务,但是在某一个时间点,CPU只能执行一个进程,而在多CPU多任务的操作系统下,由于有多个CPU,所以在某个时间点上,可以有多个进程同时运行。
进程的的基本定义是:在自身的虚拟地址空间运行的一个独立的程序,从操作系统的角度来看,所有在系统上运行的东西,都可以称为一个进程。
需要注意的是:程序和进程是有区别的,进程虽然有程序产生,但是它并不是程序,程序是一个进程指令的集合,它可以启用一个或多个进程,同时,程序只占用磁盘空间,而不占用系统运行资源,而进程仅仅占用系统内存空间,是动态的、可变的,关闭进程,占用的内存资源随之释放。
例如,用户在linux上打开一个文件、就会产生一个打开文件的进程,关闭文件,进程也随机关闭。如果在系统上启动一个服务,例如启动tomcat服务,就会产生一个对应的java的进程。而如果启动apache服务,就会产生多个httpd进程。

2.进程的分类
按照进程的功能和运行的程序分类,进程可划分为两大类:
 系统进程:可以执行内存资源分配和进程切换等管理工作;而且,该进程的运行不受用户的干预,即使是root用户也不能干预系统进程的运行。
 用户进程:通过执行用户程序、应用程序或内核之外的系统程序而产生的进程,此类进程可以在用户的控制下运行或关闭。
针对用户进程,又可以分为交互进程、批处理进程和守护进程三类。
 交互进程:由一个shell终端启动的进程,在执行过程中,需要与用户进行交互操作,可以运行于前台,也可以运行在后台。
 批处理进程:该进程是一个进程集合,负责按顺序启动其他的进程。
 守护进程:守护进程是一直运行的一种进程,经常在linux系统启动时启动,在系统关闭时终止。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。例如httpd进程,一直处于运行状态,等待用户的访问。还有经常用的crond进程,这个进程类似与windows的计划任务,可以周期性的执行用户设定的某些任务。

3.进程的属性
(1)进程的几种状态
进程在启动后,不一定马上开始运行,因而进程存在很多种状态。
 可运行状态:处于这种状态的进程,要么正在运行、要么正准备运行。
 可中断的等待状态:这类进程处于阻塞状态,一旦达到某种条件,就会变为运行态。同时该状态的进程也会由于接收到信号而被提前唤醒进入到运行态。
 不中断的等待状态:与“可中断的等待状态”含义基本类似,唯一不同的是处于这个状态的进程对信号不做响应。
 僵死状态:也就是僵死进程,每个进程在结束后都会处于僵死状态,等待父进程调用进而释放资源,处于该状态的进程已经结束,但是它的父进程还没有释放其系统资源。
 暂停状态:表明此时的进程暂时停止,来接收某种特殊处理,
(2)进程之间的关系
在linux系统中,进程ID(用PID表示)是区分不同进程的唯一标识,它们的大小是有限制的,最大ID为32768,用UID和GID分别表示启动这个进程的用户和用户组。所有的进程都是PID为1的init进程的后代,内核在系统启动的最后阶段启动init进程,因而,这个进程是linux下所有进程的父进程,用PPID表示父进程。
下面是通过ps命令输出的sendmail进程信息:
[root@localhost ~]# ps -ef|grep  sendmail
UID       PID     PPID  C   STIME  TTY        TIME               CMD
root      3614     1    0   Oct23   ?        00:00:00  sendmail: accepting connections
相对于父进程,就存在子进程,一般每个进程都必须有一个父进程,父进程与子进程之间是管理与被管理的关系,当父进程停止时,子进程也随之消失,但是子进程关闭,父进程不一定终止。
如果父进程在子进程退出之前就退出,那么所有子进程就变成的一个孤儿进程,如果没有相应的处理机制的话,这些孤儿进程就会一直处于僵死状态,资源无法释放,此时解决的办法是在启动的进程内找一个进程作为这些孤儿进程的父进程,或者直接让init进程作为它们的父进程,进而释放孤儿进程占用的资源。

二、 进程的监控与管理
         Linux下,监控和管理进程的命令有很多,下面我们以ps、top、pstree、lsof四个最常用的指令介绍如果有效的监控和管理linux下的各种进程。

2.1 利用ps命令监控系统进程
         ps是linux下最常用的进程监控命令,关于ps命令的语法和使用选项,我们在第四章已经有了详细的讲解,这里重点讲述如何利用ps指令监控和管理系统进程。
请看下面的示例:
下面是apache进程的输出信息
[root@localhost ~]#ps -ef | grep httpd
UID       PID  PPID   C STIME TTY         TIME     CMD
nobody    7272 26037  0 Nov06  ?        00:00:00 /apache2/bin/httpd -k start
nobody    7274 26037  0 Nov06  ?        00:00:00 /apache2/bin/httpd -k start
nobody    7400 26037  0 Nov06  ?        00:00:00 /apache2/bin/httpd -k start
nobody    7508 26037  0 00:09  ?        00:00:00 /apache2/bin/httpd -k start
nobody    7513 26037  0 00:09  ?        00:00:00 /apache2/bin/httpd -k start
nobody    7515 26037  0 00:09  ?        00:00:00 /apache2/bin/httpd -k start
nobody   11998 26037  0 11:14  ?        00:00:00 /apache2/bin/httpd -k start
nobody   12941 26037  0 16:25  ?        00:00:00 /apache2/bin/httpd -k start
nobody   12979 26037  0 16:44  ?        00:00:00 /apache2/bin/httpd -k start
root     26037  1     0 Oct23  ?        00:00:00 /apache2/bin/httpd -k start        
          其中,UID是用户的ID标识号,PID是进程的标识号,PPID表示父进程,STIME表示进程的启动时间,TTY表示进程所属的终端控制台,TIME表示进程启动后累计使用的CPU总时间,CMD表示正在执行的命令。
         从中可以清楚的看出,父进程和子进程的对应关系, PPID为26037的所有进程均为子进程,而PID为26037的进程是所有子进程的父进程,子进程由nobody用户启动,而父进程由root用户启动,父进程对应的PPID为1,即父进程同时为init进程的子进程。
         其实也可以通过下面的指令方式查看子进程与父进程的对应关系,请看如下操作:
[root@localhost ~]# ps auxf | grep httpd
USER      PID  %CPU %MEM    VSZ  RSS  TTY STAT  START   TIME   COMMAND
root     26037  0.0  0.1   6316  2884  ?   Ss   Oct23   0:00 /apache2/bin/httpd -k start
nobody    7272  0.0  0.1   7016  3740  ?   S    Nov06   0:00  \_ /apache2/bin/httpd -k start
nobody    7274  0.0  0.1   7016  3704  ?   S    Nov06   0:00  \_ /apache2/bin/httpd -k start
nobody    7400  0.0  0.1   7012  3676  ?   S    Nov06   0:00  \_ /apache2/bin/httpd -k start
nobody    7508  0.0  0.1   7012  3732  ?   S    00:09   0:00  \_ /apache2/bin/httpd -k start
nobody    7513  0.0  0.1   7012  3700  ?   S    00:09   0:00  \_ /apache2/bin/httpd -k start
nobody   12979  0.0  0.1   7016  3684  ?   S    16:44   0:00  \_ /apache2/bin/httpd -k start
nobody   12980  0.0  0.1   7012  3652  ?   S    16:44   0:00  \_ /apache2/bin/httpd -k start
nobody   12982  0.0  0.1   7016  3664  ?   S    16:44   0:00  \_ /apache2/bin/httpd -k start
nobody   22664  0.0  0.1   6880  3540  ?   S    22:24   0:00  \_ /apache2/bin/httpd -k start
         其中,%CPU表示进程占用的CPU百分比,%MEM表示进程占用内存的百分比,VSZ表示进程虚拟大小,RSS表示进程的实际内存(驻留集)大小(单位是页)。STAT表示进程的状态,进程的状态有很多种:用“R”表示正在运行中的进程,用“S”表示处于休眠状态的进程,用“Z”表示僵死进程,用“<”表示优先级高的进程,用“N”表示优先级较低的进程,用“s”表示父进程,用“+”表示位于后台的进程。START表示启动进程的时间。
         这个例子将进程之间的关系用树形结构形象的表示出来,可以很清楚的看到,第一个进程为父进程,而其它进程均为子进程。同时从这个输出还可以看到每个进程占用CPU、内存的百分比,还有进程所处的状态等等。

2.2 利用pstree监控系统进程
 pstree命令以树形结构显示程序和进程之间的关系,使用格式如下:
 pstree [-acnpu] [/]
 选项含义如下:
 -a  显示启动每个进程对应的完整指令,包含启动进程的路径、参数等等。
 -c  不使用精简法显示进程信息,即显示的进程中包含子进程和父进程。
 -n  根据进程PID号来排序输出,默认是以程序名称排序输出的。
 -p  显示进程的PID。
 -u  显示进程对应的用户名称。
 PID:即进程对应的PID号,或者叫进程识别号。
 user:系统用户名。
         pstree清楚的显示了程序和进程之间的关系,如果不指定进程的PID号,或者不指定用户名称,则将以init进程为根进程,显示系统的所有程序和进程信息,若指定用户或PID,则将以用户或PID为根进程,显示用户或PID对应的所有程序和进程。
举例如下:
如果想知道某个用户下都启动了哪些进程的话,pstree指令可以很容易实现,下面显示mysql用户下对应的进程信息,执行如下命令:
[root@localhost ~]# pstree mysql  
mysqld---6*[{mysqld}]
该输出显示了mysql用户下对应的进程为mysqld,并且mysqld进程拥有5个子进程(5个子进程加一个父进程,共6个进程)。
为了更详细的了解每个进程的信息,例如每个子进程和父进程对应的PID,执行如下命令:
[root@localhost ~]# pstree -c -p mysql
mysqld(18785)-+-{mysqld}(18787)
              |-{mysqld}(18788)
              |-{mysqld}(18789)
              |-{mysqld}(18790)
              |-{mysqld}(18791)
              `-{mysqld}(29625)
通过“-p、-c”参数,清楚的显示了父进程和子进程,以及它们各种的PID。
如果知道进程对应的PID,想得到进程是由哪个用户启动的,可以执行如下命令:
[root@localhost ~]# pstree -u 26037
httpd---10*[httpd(nobody)]
从上面可知,httpd进程是由nobody用户启动的。
如果要查看httpd父进程和每个子进程分别对应的PID,可以执行如下命令组合:
[root@localhost ~]# pstree -u -p 26037
httpd(26037)-+-httpd(24562,nobody)
             |-httpd(24563,nobody)
             |-httpd(24566,nobody)
             |-httpd(24567,nobody)
             |-httpd(24631,nobody)
             |-httpd(24648,nobody)
             |-httpd(24650,nobody)
             |-httpd(24654,nobody)
             |-httpd(26156,nobody)
             `-httpd(29014,nobody)
如果要得到启动httpd进程的程序路径、参数组合,执行如下命令:
[root@localhost ~]# pstree -a -u -p 26037
httpd,26037 -k start
  |-httpd,24563,nobody -k start
  |-httpd,24566,nobody -k start
  |-httpd,24567,nobody -k start
  |-httpd,24631,nobody -k start
  |-httpd,24648,nobody -k start
  |-httpd,24650,nobody -k start
  |-httpd,24654,nobody -k start
  |-httpd,26156,nobody -k start
  `-httpd,29014,nobody -k start

2.3  利用top监控系统进程
         top命令是监控系统进程必不可少的工具,与ps命令相比,top命令动态、实时的显示进程状态,而ps只能显示进程某一时刻的信息,同时,top命令提供了一个交互界面,用户可以根据需要,人性化的定制自己的输出,更清楚的了解进程的实时状态。
          关于top指令的用法,在第四章已经有了详细的介绍,这里通过几个例子,阐述一下top命令在系统进程监控中的作用和优点。
下面这个例子是某系统在某时刻执行top命令后的输出:
[root@webserver ~]# top
Tasks: 126 total,   1 running, 123 sleeping,   1 stopped,   1 zombie
Cpu(s):  0.8% us,  0.1% sy,  0.0% ni, 99.0% id,  0.0% wa,  0.0% hi,  0.0% si
Mem:   8306544k total,  8200452k used,   106092k free,   234340k buffers
Swap:  8385888k total,      160k used,  8385728k free,  7348560k cached

PID    USER     PR  NI  VIRT   RES    SHR   S  %CPU   %MEM     TIME+    COMMAND                                                               
21115  root     23   0 1236m  360m   2384   S    6     4.4     382:24.14  java                                                                  
30295  root     16   0  3552   984    760   R    1     0.0     0:00.09    top                                                                   
30118 nobody    15   0  6904  3132   1676   S    0     0.0     0:00.47    httpd
30250 nobody    15   0  6900  3088   1660   S    0     0.0     0:00.06    httpd                                                                 
  1    root     16   0  1780   552    472   S    0     0.0     0:01.25     init    
         从top命令的输出可知,此系统有java和httpd两个用户进程在运行。
进程PID为21115的java进程由root用户启动,优先级(PR)为23,占用的虚拟内存总量(VIRT)为1236M,未被换出的物理内存(RES)为360M,共享内存(SHR)为2384 kb。通过这几个选项可以了解java进程对内存的使用量,有助于系统管理员对系统虚拟内存使用状况的掌控。
         此刻java进程处于休眠状态(S),从上次更新到现在java占用cpu时间(%CPU)为6%,占用物理内存(%MEM)为4.4%,从进程启动到现在java占用cpu总时间(TIME+)为“382:24.14”,单位是1/100秒。通过了解这些信息,可以使系统管理员掌握java进程对系统CPU、物理内存的使用状况。
两个httpd进程由nobody用户启动,优先级都为15,同时都处于休眠状态。
除去这两个进程,还有top进程,也就是我们执行top命令产生的进程,从进程状态项可知,此进程处于运行状态,另一个是init进程,即所有系统进程的父进程,对应的PID为1。
         当然top的输出还有很多进程信息,这里仅仅拿出前几个进程进行重点讲解,理解其它进程的含义基本与这些相同。

2.4 利用lsof监控系统进程与程序
          lsof全名list opened files,也就是列举系统中已经被打开的文件,通过lsof,我们就可以根据文件找到对应的进程信息,也可以根据进程信息找到进程打开的文件。
lsof指令功能强大,这里介绍“-c,-g,-p,-i”这四个最常用参数的使用。更详细的介绍请参看man lsof。
 lsof filename:显示使用filename文件的进程。
如果想知道某个特定的文件由哪个进程在使用,可以通过“lsof 文件名”方式得到,例如:
[root@localhost ~]# lsof /var/log/messages
COMMAND  PID USER   FD   TYPE DEVICE  SIZE  NODE NAME
syslogd 2027 root    1w   REG    8,6 43167 31916 /var/log/messages
从这个输出可知,/var/log/messages文件是由syslogd进程在使用。
 lsof -c abc :显示abc进程现在打开的文件,例如:
 [root@localhost ~]# lsof -c nfs 
COMMAND  PID USER   FD      TYPE DEVICE SIZE NODE NAME
nfsd4   2761 root  cwd       DIR    8,3 4096    2  /
nfsd4   2761 root  rtd       DIR    8,3 4096    2  /
nfsd4   2761 root  txt    unknown                  /proc/2761/exe
nfsd    2762 root  cwd       DIR    8,3 4096    2  /
nfsd    2762 root  rtd       DIR    8,3 4096    2  /
nfsd    2762 root  txt   unknown                   /proc/2762/exe
nfsd    2763 root  cwd       DIR    8,3 4096    2  /
nfsd    2763 root  rtd       DIR    8,3 4096    2  /
nfsd    2763 root  txt   unknown                   /proc/2763/exe
    上例显示了nfs进程打开的文件信息,FD列表示文件描述符,TYPE列显示文件的类型,SIZE列显示文件的大小,NODE列显示本地文件的node码,NAME列显示文件的全路径或挂载点。
 lsof -g gid:显示指定的进程组打开的文件情况,例如:
[root@localhost ~]# lsof -g 3626
COMMAND   PID PGID  USER   FD   TYPE     DEVICE    SIZE    NODE NAME
sendmail 3626 3626 smmsp  cwd    DIR        8,8 4853760   32714 /var/spool/clientmqueue
sendmail 3626 3626 smmsp  rtd    DIR       8,10    4096       2 /
sendmail 3626 3626 smmsp  txt    REG        8,9  732356 1152124 /usr/sbin/sendmail.sendmail
sendmail 3626 3626 smmsp  mem    REG       8,10  106397 1158794 /lib/ld-2.3.4.so
sendmail 3626 3626 smmsp  mem    REG       8,10   95148 1175044 /lib/libnsl-2.3.4.so
.............省略...............
sendmail 3626 3626 smmsp    3u  unix 0xf41e5bc0            9592 socket
sendmail 3626 3626 smmsp    4wW  REG        8,8      50  523293 /var/run/sm-client.pid
其中,PGID列表示进程组的ID编号。
上面输出,显示了sendmail程序当前打开的所有文件、设备、库及套接字等。
 lsof -p PID:PID是进程号,通过进程号显示程序打开的所有文件及相关进程,例如,想知道init进程打开了哪些文件的话,可以执行“lsof -p  1”命令,输出结果如下:
[root@localhost ~]# lsof -p  1  
COMMAND PID USER   FD   TYPE DEVICE    SIZE    NODE NAME
init      1 root  cwd    DIR   8,10    4096       2 /
init      1 root  rtd    DIR   8,10    4096       2 /
init      1 root  txt    REG   8,10   32684  897823 /sbin/init
init      1 root  mem    REG   8,10   56320 2175328 /lib/libselinux.so.1
init      1 root  mem    REG   8,10  106397 1158794 /lib/ld-2.3.4.so
init      1 root  mem    REG   8,10 1454462 1161560 /lib/tls/libc-2.3.4.so
init      1 root  mem    REG   8,10   53736 1158819 /lib/libsepol.so.1
init      1 root   10u  FIFO   0,13             966 /dev/initctl

 lsof -i 通过监听指定的协议、端口、主机等信息,显示符合条件的进程信息。
使用语法为:
    lsof -i [46] [protocol][@hostname][:service|port]
 46:4代表IPv4,6代表IPv6。
 protocol:传输协议,可以是TCP或UDP。
 hostname:主机名称或者IP地址。
 service:进程的服务名,例如nfs、ssh、ftp等。
 port:系统中服务对应的端口号。例如http服务默认对应80,ssh服务默认对应22等等。
例如:
显示系统中tcp协议对应的25端口进程信息:
[root@localhost ~]# lsof -i tcp:25
COMMAND   PID USER    FD   TYPE  DEVICE SIZE   NODE         NAME
sendmail 2252 root    4u   IPv4   5874         TCP   localhost:smtp (LISTEN)
显示系统中80端口对应的进程信息:
[root@localhost ~]# lsof -i :80
COMMAND   PID   USER      FD   TYPE  DEVICE SIZE   NODE     NAME
httpd   16474   nobody    3u   IPv6  7316069       TCP   *:http (LISTEN)
httpd   16475   nobody    3u   IPv6  7316069       TCP   *:http (LISTEN)
httpd   16578   nobody    3u   IPv6  7316069       TCP   *:http (LISTEN)
 显示本机udp协议对应的53端口开启的进程信息:
[root@localhost ~]# lsof -i [email protected]:53
COMMAND   PID  USER     FD   TYPE   DEVICE  SIZE NODE      NAME
named    21322 named   20u   IPv4   9130640      UDP   localhost:domain
   通过lsof命令能够清楚的了解进程和文件以及程序之间的对应关系,熟练掌握lsof的使用,对linux的进程管理有很大帮助。