通常,現在的操作系統都支持多任務,意味著操作系統(給用戶)造成了一種假象,(讓用戶覺得) 它同時能夠做多件事情,事實上,它是快速地輪換執行這些任務的。Linux 內核通過使用進程,來 管理多任務。通過進程,Linux 安排不同的程序等待使用 CPU。
有時候,計算機變得呆滯,運行緩慢,或者一個應用程序停止響應。在這一章中,我們將看一些 可用的命令行工具,這些工具幫助我們查看程序的執行狀態,以及怎樣終止行為不當的進程。
這一章將介紹以下命令:
* ps – 報告當前進程快照
* top – 顯示任務
* jobs – 列出活躍的任務
* bg – 把一個任務放到后臺執行
* fg – 把一個任務放到前臺執行
* kill – 給一個進程發送信號
* killall – 殺死指定名字的進程
* shutdown – 關機或重啟系統
### 進程是怎樣工作的
當系統啟動的時候,內核先把一些它自己的程序初始化為進程,然后運行一個叫做 init 的程序。init, 依次地,再運行一系列的稱為 init 腳本的 shell 腳本(位于/etc),它們可以啟動所有的系統服務。 其中許多系統服務以守護(daemon)程序的形式實現,守護程序僅在后臺運行,沒有任何用戶接口。 這樣,即使我們沒有登錄系統,至少系統也在忙于執行一些例行事務。
一個程序可以發動另一個程序,這個事實在進程方案中,表述為一個父進程創建了一個子進程。
內核維護每個進程的信息,以此來保持事情有序。例如,系統分配給每個進程一個數字,這個數字叫做 進程 ID 或 PID。PID 號按升序分配,init 進程的 PID 總是1。內核也對分配給每個進程的內存進行跟蹤。 像文件一樣,進程也有所有者和用戶 ID,有效用戶 ID,等等。
### 查看進程
查看進程,最常使用地命令(有幾個命令)是 ps。ps 程序有許多選項,它最簡單地使用形式是這樣的:
~~~
[me@linuxbox ~]$ ps
PID TTY TIME CMD
5198 pts/1 00:00:00 bash
10129 pts/1 00:00:00 ps
~~~
上例中,列出了兩個進程,進程 5198 和進程 10129,各自代表命令 bash 和 ps。正如我們所看到的, 默認情況下,ps 不會顯示很多進程信息,只是列出與當前終端會話相關的進程。為了得到更多信息, 我們需要加上一些選項,但是在這樣做之前,我們先看一下 ps 命令運行結果的其它字段。 TTY 是 “Teletype” 的簡寫,是指進程的控制終端。這里,Unix 展示它的年齡。TIME 字段表示 進程所消耗的 CPU 時間數量。正如我們所看到的,這兩個進程使計算機工作起來很輕松。
如果給 ps 命令加上選項,我們可以得到更多關于系統運行狀態的信息:
~~~
[me@linuxbox ~]$ ps x
PID TTY STAT TIME COMMAND
2799 ? Ssl 0:00 /usr/libexec/bonobo-activation-server –ac
2820 ? Sl 0:01 /usr/libexec/evolution-data-server-1.10 --
and many more...
~~~
加上 “x” 選項(注意沒有開頭的 “-“ 字符),告訴 ps 命令,展示所有進程,不管它們由什么 終端(如果有的話)控制。在 TTY 一欄中出現的 “?” ,表示沒有控制終端。使用這個 “x” 選項,可以 看到我們所擁有的每個進程的信息。
因為系統中正運行著許多進程,所以 ps 命令的輸出結果很長。這經常很有幫助,要是把 ps 的輸出結果 管道到 less 命令,借助 less 工具,更容易瀏覽。一些選項組合也會產生很長的輸出結果,所以最大化 終端仿真器窗口,也是一個好主意。
輸出結果中,新添加了一欄,標題為 STAT 。STAT 是 “state” 的簡寫,它揭示了進程當前狀態:
表11-1: 進程狀態
| 狀態 | 意義 |
| --- | --- |
| R | 運行。這意味著,進程正在運行或準備運行。 |
| S | 正在睡眠。 進程沒有運行,而是,正在等待一個事件, 比如說,一個按鍵或者網絡數據包。 |
| D | 不可中斷睡眠。進程正在等待 I/O,比方說,一個磁盤驅動器的 I/O。 |
| T | 已停止. 已經指示進程停止運行。稍后介紹更多。 |
| Z | 一個死進程或“僵尸”進程。這是一個已經終止的子進程,但是它的父進程還沒有清空它。 (父進程沒有把子進程從進程表中刪除) |
| < | 一個高優先級進程。這可能會授予一個進程更多重要的資源,給它更多的 CPU 時間。 進程的這種屬性叫做 niceness。具有高優先級的進程據說是不好的(less nice), 因為它占用了比較多的 CPU 時間,這樣就給其它進程留下很少時間。 |
| N | 低優先級進程。 一個低優先級進程(一個“好”進程)只有當其它高優先級進程執行之后,才會得到處理器時間。 |
進程狀態信息之后,可能還跟隨其他的字符。這表示各種外來進程的特性。詳細信息請看 ps 手冊頁。
另一個流行的選項組合是 “aux”(不帶開頭的”-“字符)。這會給我們更多信息:
~~~
[me@linuxbox ~]$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 2136 644 ? Ss Mar05 0:31 init
root 2 0.0 0.0 0 0 ? S< Mar05 0:00 [kt]
and many more...
~~~
這個選項組合,能夠顯示屬于每個用戶的進程信息。使用這個選項,可以喚醒 “BSD 風格” 的輸出結果。 Linux 版本的 ps 命令,可以模擬幾個不同 Unix 版本中的 ps 程序的行為。通過這些選項,我們得到 這些額外的列。
表11-2: BSD 風格的 ps 命令列標題
| 標題 | 意思 |
| --- | --- |
| USER | 用戶 ID. 進程的所有者。 |
| %CPU | 以百分比表示的 CPU 使用率 |
| %MEM | 以百分比表示的內存使用率 |
| VSZ | 虛擬內存大小 |
| RSS | 進程占用的物理內存的大小,以千字節為單位。 |
| START | 進程運行的起始時間。若超過24小時,則用天表示。 |
### 用 top 命令動態查看進程
雖然 ps 命令能夠展示許多計算機運行狀態的信息,但是它只是提供,ps 命令執行時刻的機器狀態快照。 為了看到更多動態的信息,我們使用 top 命令:
~~~
[me@linuxbox ~]$ top
~~~
top 程序連續顯示系統進程更新的信息(默認情況下,每三分鐘更新一次),”top”這個名字 來源于這個事實,top 程序是用來查看系統中“頂端”進程的。top 顯示結果由兩部分組成: 最上面是系統概要,下面是進程列表,以 CPU 的使用率排序。
~~~
top - 14:59:20 up 6:30, 2 users, load average: 0.07, 0.02, 0.00
Tasks: 109 total, 1 running, 106 sleeping, 0 stopped, 2 zombie
Cpu(s): 0.7%us, 1.0%sy, 0.0%ni, 98.3%id, 0.0%wa, 0.0%hi, 0.0%si
Mem: 319496k total, 314860k used, 4636k free, 19392k buff
Swap: 875500k total, 149128k used, 726372k free, 114676k cach
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6244 me 39 19 31752 3124 2188 S 6.3 1.0 16:24.42 trackerd
....
~~~
其中系統概要包含許多有用信息。下表是對系統概要的說明:
表11-3: top 命令信息字段
| 行號 | 字段 | 意義 |
| --- | --- | --- |
| 1 | top | 程序名。 |
14:59:20 | 當前時間。 |
up 6:30 | 這是正常運行時間。它是計算機從上次啟動到現在所運行的時間。 在這個例子里,系統已經運行了六個半小時。 |
2 users | 有兩個用戶登錄系統。 |
load average: | 加載平均值是指,等待運行的進程數目,也就是說,處于運行狀態的進程個數, 這些進程共享 CPU。展示了三個數值,每個數值對應不同的時間周期。第一個是最后60秒的平均值, 下一個是前5分鐘的平均值,最后一個是前15分鐘的平均值。若平均值低于1.0,則指示計算機 工作不忙碌。 |
| 2 | Tasks: | 總結了進程數目和各種進程狀態。 |
| 3 | Cpu(s): | 這一行描述了 CPU 正在執行的進程的特性。 |
0.7%us | 0.7% of the CPU is being used for user processes. 這意味著進程在內核之外。 |
1.0%sy | 1.0%的 CPU 時間被用于系統(內核)進程。 |
0.0%ni | 0.0%的 CPU 時間被用于"nice"(低優先級)進程。 |
98.3%id | 98.3%的 CPU 時間是空閑的。 |
0.0%wa | 0.0%的 CPU 時間來等待 I/O。 |
| 4 | Mem: | 展示物理內存的使用情況。 |
| 5 | Swap: | 展示交換分區(虛擬內存)的使用情況。 |
top 程序接受一系列從鍵盤輸入的命令。兩個最有趣的命令是 h 和 q。h,顯示程序的幫助屏幕,q, 退出 top 程序。
兩個主要的桌面環境都提供了圖形化應用程序,來顯示與 top 程序相似的信息 (和 Windows 中的任務管理器差別不多),但是我覺得 top 程序要好于圖形化的版本, 因為它運行速度快,并且消費很少的系統資源。畢竟,我們的系統監測程序不能成為 系統怠工的源泉,而這是我們試圖追蹤的信息。
### 控制進程
現在我們可以看到和監測進程,然后得到一些對它們的控制權。為了我們的實驗,我們將使用 一個叫做 xlogo 的小程序,作為我們的實驗品。這個 xlogo 程序是 X 窗口系統 (底層引擎使圖形界面顯示在屏幕上)提供的實例程序,這個實例簡單地顯示一個大小可調的 包含 X 標志的窗口。首先,我們需要知道測試的主題:
~~~
[me@linuxbox ~]$ xlogo
~~~
命令執行之后,一個包含 X 標志的小窗口應該出現在屏幕的某個位置上。在一些系統中,xlogo 命令 會打印一條警告信息,但是不用理會它。
小貼士:如果你的系統不包含 xlogo 程序,試著用 gedit 或者 kwrite 來代替。
通過調整它的窗口大小,我們能夠證明 xlogo 程序正在運行。如果這個標志以新的尺寸被重畫, 則這個程序正在運行。
注意,為什么我們的 shell 提示符還沒有返回?這是因為 shell 正在等待這個程序結束, 就像到目前為止我們用過的其它所有程序一樣。如果我們關閉 xlogo 窗口,shell 提示符就返回了。
### 中斷一個進程
我們再運行 xlogo 程序一次,觀察一下發生了什么事。首先,執行 xlogo 命令,并且 證實這個程序正在運行。下一步,回到終端窗口,按下 Ctrl-c。
~~~
[me@linuxbox ~]$ xlogo
[me@linuxbox ~]$
~~~
在一個終端中,輸入 Ctrl-c,中斷一個程序。這意味著,我們禮貌地要求終止這個程序。 輸入 Ctrl-c 之后,xlogo 窗口關閉,shell 提示符返回。
通過這個技巧,許多(但不是全部)命令行程序可以被中斷。
### 把一個進程放置到后臺(執行)
比方說,我們想讓 shell 提示符返回,卻沒有終止 xlogo 程序。為達到這個目的,我們把 這個程序放到后臺執行。把終端看作是一個有前臺(表層放置可見的事物,像 shell 提示符) 和后臺(表層之下放置隱藏的事物)(的設備)。啟動一個程序,讓它立即在后臺 運行,我們在程序命令之后,加上”&”字符:
~~~
[me@linuxbox ~]$ xlogo &
[1] 28236
[me@linuxbox ~]$
~~~
執行命令之后,這個 xlogo 窗口出現,并且 shell 提示符返回,同時打印一些有趣的數字。 這條信息是 shell 特性的一部分,叫做工作控制。通過這條信息,shell 告訴我們,已經啟動了 工作號為1(“[1]”),PID 為28236的程序。如果我們運行 ps 命令,可以看到我們的進程:
~~~
[me@linuxbox ~]$ ps
PID TTY TIME CMD
10603 pts/1 00:00:00 bash
28236 pts/1 00:00:00 xlogo
28239 pts/1 00:00:00 ps
~~~
工作控制,這個 shell 功能可以列出從終端中啟動的任務。執行 jobs 命令,我們可以看到這個輸出列表:
~~~
[me@linuxbox ~]$ jobs
[1]+ Running xlogo &
~~~
結果顯示我們有一個任務,編號為“1”,它正在運行,并且這個任務的命令是 xlogo &。
### 進程返回到前臺
一個在后臺運行的進程對一切來自鍵盤的輸入都免疫,也不能用 Ctrl-c 來中斷它。使用 fg 命令,讓一個進程返回前臺執行:
~~~
[me@linuxbox ~]$ jobs
[1]+ Running xlogo &
[me@linuxbox ~]$ fg %1
xlogo
~~~
fg 命令之后,跟隨著一個百分號和工作序號(叫做 jobspec)。如果我們只有一個后臺任務,那么 jobspec 是可有可無的。輸入 Ctrl-c 來終止 xlogo 程序。
### 停止一個進程
有時候,我們想要停止一個進程,而沒有終止它。這樣會把一個前臺進程移到后臺等待。 輸入 Ctrl-z,可以停止一個前臺進程。讓我們試一下。在命令提示符下,執行 xlogo 命令, 然后輸入 Ctrl-z:
~~~
[me@linuxbox ~]$ xlogo
[1]+ Stopped xlogo
[me@linuxbox ~]$
~~~
停止 xlogo 程序之后,通過調整 xlogo 的窗口大小,我們可以證實這個程序已經停止了。 它看起來像死掉了一樣。使用 fg 命令,可以恢復程序到前臺運行,或者用 bg 命令把程序移到后臺。
~~~
[me@linuxbox ~]$ bg %1
[1]+ xlogo &
[me@linuxbox ~]$
~~~
和 fg 命令一樣,如果只有一個任務的話,jobspec 參數是可選的。
因為把一個進程從前臺移到后臺很方便,如果我們從命令行啟動一個圖形界面的程序,但是 忘記把它放到后臺執行,即沒有在命令后加上字符”&”,(也不用擔心)。
為什么要從命令行啟動一個圖形界面程序呢?有兩個原因。第一個,你想要啟動的程序,可能 沒有在窗口管理器的菜單中列出來(比方說 xlogo)。第二個,從命令行啟動一個程序, 你能夠看到一些錯誤信息,如果從窗口系統中運行程序的話,這些信息是不可見的。有時候, 一個程序不能從圖形界面菜單中啟動。這時候,應該從命令行中啟動它。我們可能會看到 錯誤信息,這些信息揭示了問題所在。一些圖形界面程序還有許多有意思并且有用的命令行選項。
### Signals
kill 命令被用來“殺死”程序。這樣我們就可以終止需要殺死的程序。這里有一個實例:
~~~
[me@linuxbox ~]$ xlogo &
[1] 28401
[me@linuxbox ~]$ kill 28401
[1]+ Terminated xlogo
~~~
首先,我們在后臺啟動 xlogo 程序。shell 打印出 jobspec 和這個后臺進程的 PID。下一步,我們使用 kill 命令,并且指定我們想要終止的進程 PID。也可以用 jobspec(例如,“%1”)來代替 PID。
雖然這個命令很直接了當,但不僅僅這些。這個 kill 命令不是確切地“殺死”程序,而是給程序 發送信號。信號是操作系統與程序之間進行通信,所采用的幾種方式中的一種。我們已經看到 信號,在使用 Ctrl-c 和 Ctrl-z 的過程中。當終端接受了其中一個按鍵組合后,它會給在前端運行 的程序發送一個信號。在使用 Ctrl-c 的情況下,會發送一個叫做 INT(中斷)的信號;當使用 Ctrl-z 時,則發送一個叫做 TSTP(終端停止)的信號。程序,反過來,傾聽信號的到來,當程序 接到信號之后,則做出響應。一個程序能夠傾聽和響應信號,這個事實允許一個程序做些事情, 比如,當程序接到一個終止信號時,它可以保存所做的工作。
### 通過 kill 命令給進程發送信號
kill 命令被用來給程序發送信號。它最常見的語法形式看起來像這樣:
~~~
kill [-signal] PID...
~~~
如果在命令行中沒有指定信號,那么默認情況下,發送 TERM(終止)信號。kill 命令被經常 用來發送以下命令:
表 11-4: 常用信號
| 編號 | 名字 | 含義 |
| 1 | HUP | 掛起。這是美好往昔的痕跡,那時候終端機通過電話線和調制解調器連接到 遠端的計算機。這個信號被用來告訴程序,控制的終端機已經“掛起”。 通過關閉一個終端會話,可以說明這個信號的作用。發送這個信號到終端機上的前臺程序,程序會終止。
許多守護進程也使用這個信號,來重新初始化。這意味著,當發送這個信號到一個守護進程后, 這個進程會重新啟動,并且重新讀取它的配置文件。Apache 網絡服務器守護進程就是一個例子。
|
| 2 | INT | 中斷。實現和 Ctrl-c 一樣的功能,由終端發送。通常,它會終止一個程序。 |
| 9 | KILL | 殺死。這個信號很特別。鑒于進程可能會選擇不同的方式,來處理發送給它的 信號,其中也包含忽略信號,這樣呢,從不發送 Kill 信號到目標進程。而是內核立即終止 這個進程。當一個進程以這種方式終止的時候,它沒有機會去做些“清理”工作,或者是保存勞動成果。 因為這個原因,把 KILL 信號看作殺手锏,當其它終止信號失敗后,再使用它。 |
| 15 | TERM | 終止。這是 kill 命令發送的默認信號。如果程序仍然“活著”,可以接受信號,那么 這個信號終止。 |
| 18 | CONT | 繼續。在停止一段時間后,進程恢復運行。 |
| 19 | STOP | 停止。這個信號導致進程停止運行,而沒有終止。像 KILL 信號,它不被 發送到目標進程,因此它不能被忽略。 |
讓我們實驗一下 kill 命令:
~~~
[me@linuxbox ~]$ xlogo &
[1] 13546
[me@linuxbox ~]$ kill -1 13546
[1]+ Hangup xlogo
~~~
在這個例子里,我們在后臺啟動 xlogo 程序,然后通過 kill 命令,發送給它一個 HUP 信號。 這個 xlogo 程序終止運行,并且 shell 指示這個后臺進程已經接受了一個掛起信號。在看到這條 信息之前,你可能需要多按幾次 enter 鍵。注意,既可以用號碼,也可以用名字,不過要在名字前面 加上字母“SIG”,來指定所要發送的信號。
~~~
[me@linuxbox ~]$ xlogo &
[1] 13546
[me@linuxbox ~]$ kill -1 13546
[1]+ Hangup xlogo
~~~
重復上面的例子,試著使用其它的信號。記住,你也可以用 jobspecs 來代替 PID。
進程,和文件一樣,擁有所有者,所以為了能夠通過 kill 命令來給進程發送信號, 你必須是進程的所有者(或者是超級用戶)。
除了上表列出的 kill 命令最常使用的信號之外,還有一些系統頻繁使用的信號。以下是其它一些常用 信號列表:
表 11-5: 其它常用信號
| 編號 | 名字 | 含義 |
| 3 | QUIT | 退出 |
| 11 | SEGV | 段錯誤。如果一個程序非法使用內存,就會發送這個信號。也就是說, 程序試圖寫入內存,而這個內存空間是不允許此程序寫入的。 |
| 20 | TSTP | 終端停止。當按下 Ctrl-z 組合鍵后,終端發送這個信號。不像 STOP 信號, TSTP 信號由目標進程接收,且可能被忽略。 |
| 28 | WINCH | 改變窗口大小。當改變窗口大小時,系統會發送這個信號。 一些程序,像 top 和 less 程序會響應這個信號,按照新窗口的尺寸,刷新顯示的內容。 |
為了滿足讀者的好奇心,通過下面的命令可以得到一個完整的信號列表:
~~~
[me@linuxbox ~]$ kill -l
~~~
### 通過 killall 命令給多個進程發送信號
也有可能通過 killall 命令,給匹配特定程序或用戶名的多個進程發送信號。下面是 killall 命令的語法形式:
~~~
killall [-u user] [-signal] name...
~~~
為了說明情況,我們將啟動一對 xlogo 程序的實例,然后再終止它們:
~~~
[me@linuxbox ~]$ xlogo &
[1] 18801
[me@linuxbox ~]$ xlogo &
[2] 18802
[me@linuxbox ~]$ killall xlogo
[1]- Terminated xlogo
[2]+ Terminated xlogo
~~~
記住,和 kill 命令一樣,你必須擁有超級用戶權限才能給不屬于你的進程發送信號。
### 更多和進程相關的命令
因為監測進程是一個很重要的系統管理任務,所以有許多命令與它相關。玩玩下面幾個命令:
表11-6: 其它與進程相關的命令
| 命令名 | 命令描述 |
| pstree | 輸出一個樹型結構的進程列表,這個列表展示了進程間父/子關系。 |
| vmstat | 輸出一個系統資源使用快照,包括內存,交換分區和磁盤 I/O。 為了看到連續的顯示結果,則在命令名后加上延時的時間(以秒為單位)。例如,“vmstat 5”。 終止輸出,按下 Ctrl-c 組合鍵。 |
| xload | 一個圖形界面程序,可以畫出系統負載的圖形。 |
| tload | 與 xload 程序相似,但是在終端中畫出圖形。使用 Ctrl-c,來終止輸出。
|
- 第一章:引言
- 第二章:什么是shell
- 第三章:文件系統中跳轉
- 第四章:研究操作系統
- 第五章:操作文件和目錄
- 第六章:使用命令
- 第七章:重定向
- 第八章:從shell眼中看世界
- 第九章:鍵盤高級操作技巧
- 第十章:權限
- 第十一章:進程
- 第十二章:shell環境
- 第十三章:VI簡介
- 第十四章:自定制shell提示符
- 第十五章:軟件包管理
- 第十六章:存儲媒介
- 第十七章:網絡系統
- 第十八章:查找文件
- 第十九章:歸檔和備份
- 第二十章:正則表達式
- 第二十一章:文本處理
- 第二十二章:格式化輸出
- 第二十三章:打印
- 第二十四章:編譯程序
- 第二十五章:編寫第一個shell腳本
- 第二十六章:啟動一個項目
- 第二十七章:自頂向下設計
- 第二十八章:流程控制 if分支結構
- 第二十九章:讀取鍵盤輸入
- 第三十章:流程控制 while/until 循環
- 第三十一章:疑難排解
- 第三十二章:流程控制 case分支
- 第三十三章:位置參數
- 第三十四章:流程控制 for循環
- 第三十五章:字符串和數字
- 第三十六章:數組
- 第三十七章:奇珍異寶