一 、程式的概念和分類
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] [<PID>/<user>]
 選項含義如下:
 -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 udp@127.0.0.1:53
COMMAND   PID  USER     FD   TYPE   DEVICE  SIZE NODE      NAME
named    21322 named   20u   IPv4   9130640      UDP   localhost:domain
   通過lsof命令能夠清楚的瞭解程式和檔案以及程式之間的對應關係,熟練掌握lsof的使用,對linux的程式管理有很大幫助。