top 命令詳解html
進程狀態詳解node
top命令是Linux下經常使用的性能分析工具,可以實時顯示系統中各個進程的資源佔用情況,相似於Windows的任務管理器。下面詳細介紹它的使用方法。shell
top - 20:52:06 up 132 days, 59 min, 1 user, load average: 0.01, 0.02, 0.00 |
前五行是系統總體的統計信息。第一行是任務隊列信息,同 uptime 命令的執行結果。其內容以下:安全
01:06:48 | 當前時間 |
up 1:22 | 系統運行時間,格式爲時:分 |
1 user | 當前登陸用戶數 |
load average: 0.06, 0.60, 0.48 | 系統負載,即任務隊列的平均長度。 三個數值分別爲 1分鐘、5分鐘、15分鐘前到如今的平均值。 |
第2、三行爲進程和CPU的信息。當有多個CPU時,這些內容可能會超過兩行。內容以下:網絡
Tasks: 29 total | 進程總數 |
1 running | 正在運行的進程數 |
28 sleeping | 睡眠的進程數 |
0 stopped | 中止的進程數 |
0 zombie | 殭屍進程數 |
Cpu(s): 0.3% us | 用戶空間佔用CPU百分比 |
1.0% sy | 內核空間佔用CPU百分比 |
0.0% ni | 用戶進程空間內改變過優先級的進程佔用CPU百分比 |
98.7% id | 空閒CPU百分比 |
0.0% wa | 等待輸入輸出的CPU時間百分比 |
0.0% hi | |
0.0% si |
最後兩行爲內存信息。內容以下:session
Mem: 191272k total | 物理內存總量 |
173656k used | 使用的物理內存總量 |
17616k free | 空閒內存總量 |
22052k buffers | 用做內核緩存的內存量 |
Swap: 192772k total | 交換區總量 |
0k used | 使用的交換區總量 |
192772k free | 空閒交換區總量 |
123988k cached | 緩衝的交換區總量。 內存中的內容被換出到交換區,然後又被換入到內存,但使用過的交換區還沒有被覆蓋, 該數值即爲這些內容已存在於內存中的交換區的大小。 相應的內存再次被換出時可沒必要再對交換區寫入。 |
統計信息區域的下方顯示了各個進程的詳細信息。首先來認識一下各列的含義。數據結構
序號 | 列名 | 含義 |
a | PID | 進程id |
b | PPID | 父進程id |
c | RUSER | Real user name |
d | UID | 進程全部者的用戶id |
e | USER | 進程全部者的用戶名 |
f | GROUP | 進程全部者的組名 |
g | TTY | 啓動進程的終端名。不是從終端啓動的進程則顯示爲 ? |
h | PR | 優先級 |
i | NI | nice值。負值表示高優先級,正值表示低優先級 |
j | P | 最後使用的CPU,僅在多CPU環境下有意義 |
k | %CPU | 上次更新到如今的CPU時間佔用百分比 |
l | TIME | 進程使用的CPU時間總計,單位秒 |
m | TIME+ | 進程使用的CPU時間總計,單位1/100秒 |
n | %MEM | 進程使用的物理內存百分比 |
o | VIRT | 進程使用的虛擬內存總量,單位kb。VIRT=SWAP+RES |
p | SWAP | 進程使用的虛擬內存中,被換出的大小,單位kb。 |
q | RES | 進程使用的、未被換出的物理內存大小,單位kb。RES=CODE+DATA |
r | CODE | 可執行代碼佔用的物理內存大小,單位kb |
s | DATA | 可執行代碼之外的部分(數據段+棧)佔用的物理內存大小,單位kb |
t | SHR | 共享內存大小,單位kb |
u | nFLT | 頁面錯誤次數 |
v | nDRT | 最後一次寫入到如今,被修改過的頁面數。 |
w | S | 進程狀態。 D=不可中斷的睡眠狀態 R=運行 S=睡眠 T=跟蹤/中止 Z=殭屍進程 |
x | COMMAND | 命令名/命令行 |
y | WCHAN | 若該進程在睡眠,則顯示睡眠中的系統函數名 |
z | Flags | 任務標誌,參考 sched.h |
默認狀況下僅顯示比較重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 列。能夠經過下面的快捷鍵來更改顯示內容。多線程
經過 f 鍵能夠選擇顯示的內容。按 f 鍵以後會顯示列的列表,按 a-z 便可顯示或隱藏對應的列,最後按回車鍵肯定。
按 o 鍵能夠改變列的顯示順序。按小寫的 a-z 能夠將相應的列向右移動,而大寫的 A-Z 能夠將相應的列向左移動。最後按回車鍵肯定。
按大寫的 F 或 O 鍵,而後按 a-z 能夠將進程按照相應的列進行排序。而大寫的 R 鍵能夠將當前的排序倒轉。
命令使用
1. 工具(命令)名稱
top
2.工具(命令)做用
顯示系統當前的進程和其餘 情況; top是一個動態顯示過程,便可以經過用戶按鍵來不斷刷新當前狀態.若是在前臺執行該命令,它將獨佔前臺,直到用戶終止該程序爲止. 比較準確的說,top命令提供了實時的對系統處理器的狀態監視.它將顯示系統中CPU最「敏感」的任務列表.該命令能夠按CPU使用.內存使用和執行時間 對任務進行排序;並且該命令的不少特性均可以經過交互式命令或者在我的定製文件中進行設定.
3.環境設置
在Linux下使用。
4.使用方法
4.1使用格式
top [-] [d] [p] [q] [c] [C] [S] [s] [n]
4.2參數說明
d 指定每兩次屏幕信息刷新之間的時間間隔。固然用戶可使用s交互命令來改變之。
p 經過指定監控進程ID來僅僅監控某個進程的狀態。
q該選項將使top沒有任何延遲的進行刷新。若是調用程序有超級用戶權限,那麼top將以儘量高的優先級運行。
S 指定累計模式
s 使top命令在安全模式中運行。這將去除交互命令所帶來的潛在危險。
i 使top不顯示任何閒置或者僵死進程。
c 顯示整個命令行而不僅是顯示命令名
4.3其餘
下面介紹在top命令執行過程當中可使用的一些交互命令。從使用角度來看,熟練的掌握這些命令比掌握選項還重要一些。這些命令都是單字母的,若是在命令行選項中使用了s選項,則可能其中一些命令會被屏蔽掉。
Ctrl+L 擦除而且重寫屏幕。
h或者? 顯示幫助畫面,給出一些簡短的命令總結說明。
k 終止一個進程。系統將提示用戶輸入須要終止的進程PID,以及須要發送給該進程什麼樣的信號。通常的終止進程可使用15信號;若是不能正常結束那就使用信號9強制結束該進程。默認值是信號15。在安全模式中此命令被屏蔽。
i 忽略閒置和僵死進程。這是一個開關式命令。
q 退出程序。
r 從新安排一個進程的優先級別。系統提示用戶輸入須要改變的進程PID以及須要設置的進程優先級值。輸入一個正值將使優先級下降,反之則可使該進程擁有更高的優先權。默認值是10。
S 切換到累計模式。
s 改變兩次刷新之間的延遲時間。系統將提示用戶輸入新的時間,單位爲s。若是有小數,就換算成m s。輸入0值則系統將不斷刷新,默認值是5 s。須要注意的是若是設置過小的時間,極可能會引發不斷刷新,從而根原本不及看清顯示的狀況,並且系統負載也會大大增長。
f或者F 從當前顯示中添加或者刪除項目。
o或者O 改變顯示項目的順序。
l 切換顯示平均負載和啓動時間信息。
m 切換顯示內存信息。
t 切換顯示進程和CPU狀態信息。
c 切換顯示命令名稱和完整命令行。
M 根據駐留內存大小進行排序。
P 根據CPU使用百分比大小進行排序。
T 根據時間/累計時間進行排序。
W 將當前設置寫入~/.toprc文件中。這是寫top配置文件的推薦方法。
完
用ps 的 – l 選項,獲得更詳細的進程信息:
(1)F(Flag):一系列數字的和,表示進程的當前狀態。這些數字的含義爲:
00:若單獨顯示,表示此進程已被終止。
01:進程是核心進程的一部分,常駐於系統主存。如:sched,vhand,bdflush。
02:Parent is tracing process.
04 :Tracing parent's signal has stopped the process; the parent is waiting ( ptrace(S)).
10:進程在優先級低於或等於25時,進入休眠狀態,並且不能用信號喚醒,例如在等待一個inode被建立時。
20:進程被裝入主存(primary memory)
40:進程被鎖在主存,在事務完成前不能被置換。
(2) 進程狀態:S(state)
O:進程正在處理器運行,這個狀態歷來木見過.
S:休眠狀態(sleeping)
R:等待運行(runable)R Running or runnable (on run queue) 進程處於運行或就緒狀態
I:空閒狀態(idle)
Z:殭屍狀態(zombie)
T:跟蹤狀態(Traced)
B:進程正在等待更多的內存頁
D:不可中斷的深度睡眠,通常由IO引發,同步IO在作讀或寫操做時,cpu不能作其它事情,只能等待,這時進程處於這種狀態,若是程序採用異步IO,這種狀態應該就不多見到了
(3)C(cpu usage):cpu利用率的估算值
1.2 使用Top命令中的S 字段
pid user pr ni virt res shr s %cpu %mem time+ command
11423 oracle 16 0 627m 170m 168m R 32 9.0 4110:21 oracle
3416 oracle 15 0 650m 158m 138m S 0 8.4 0:07.12 oracle
11167 oracle 15 0 626m 151m 149m S 0 8.0 400:20.77 oracle
11429 oracle 15 0 626m 148m 147m S 0 7.9 812:05.71 oracle
3422 oracle 18 0 627m 140m 137m S 0 7.4 1:12.23 oracle
1230 oracle 15 0 639m 107m 96m S 0 5.7 0:10.00 oracle
637 oracle 15 0 629m 76m 73m S 0 4.0 0:04.31 oracle
二. 進程狀態說明
2.1 R (task_running) : 可執行狀態
只有在該狀態的進程纔可能在CPU上運行。而同一時刻可能有多個進程處於可執行狀態,這些進程的task_struct結構(進程控 制塊)被放入對應CPU的可執行隊列中(一個進程最多隻能出如今一個CPU的可執行隊列中)。進程調度器的任務就是從各個CPU的可執行隊列中分別選擇一 個進程在該CPU上運行。
不少操做系統教科書將正在CPU上執行的進程定義爲RUNNING狀態、而將可執行可是還沒有被調度執行的進程定義爲READY狀態,這兩種狀態在linux下統一爲 TASK_RUNNING狀態。
2.2 S (task_interruptible): 可中斷的睡眠狀態
處於這個狀態的進程由於等待某某事件的發生(好比等待socket鏈接、等待信號量),而被掛起。這些進程的task_struct 結構被放入對應事件的等待隊列中。當這些事件發生時(由外部中斷觸發、或由其餘進程觸發),對應的等待隊列中的一個或多個進程將被喚醒。
經過ps命令咱們會看到,通常狀況下,進程列表中的絕大多數進程都處於task_interruptible狀態(除非機器的負載很高)。畢竟CPU就這麼一兩個,進程動輒幾十上百個,若是不是絕大多數進程都在睡眠,CPU又怎麼響應得過來。
2.3 D (task_uninterruptible): 不可中斷的睡眠狀態
與task_interruptible狀態相似,進程處於睡眠狀態,可是此刻進程是不可中斷的。不可中斷,指的並非CPU不響應外部硬件的中斷,而是指進程不響應異步信號。
絕 大多數狀況下,進程處在睡眠狀態時,老是應該可以響應異步信號的。可是uninterruptible sleep 狀態的進程不接受外來的任何信號,所以沒法用kill殺掉這些處於D狀態的進程,不管是」kill」, 「kill -9″仍是」kill -15″,這種狀況下,一個可選的方法就是reboot。
處於uninterruptible sleep狀態的進程一般是在等待IO,好比磁盤IO,網絡IO,其餘外設IO,若是進程正在等待的IO在較長的時間內都沒有響應,那麼就被ps看到了, 同時也就意味着頗有可能有IO出了問題,多是外設自己出了故障,也多是好比掛載的遠程文件系統已經不可訪問了.
而task_uninterruptible狀態存在的意義就在於,內核的某些處理流程是不能被打斷的。若是響應異步信號,程序的執 行流程中就會被插入一段用於處理異步信號的流程(這個插入的流程可能只存在於內核態,也可能延伸到用戶態),因而原有的流程就被中斷了。
在進程對某些硬件進行操做時(好比進程調用read系統調用對某個設備文件進行讀操做,而read系統調用最終執行到對應設備驅動的 代碼,並與對應的物理設備進行交互),可能須要使用task_uninterruptible狀態對進程進行保護,以免進程與設備交互的過程被打斷,造 成設備陷入不可控的狀態。這種狀況下的task_uninterruptible狀態老是很是短暫的,經過ps命令基本上不可能捕捉到。
咱們經過vmstat 命令中procs下的b 能夠來查看是否有處於uninterruptible 狀態的進程。 該命令只能顯示數量。
In computer operating systems terminology, a sleeping process can either be interruptible (woken via signals) or uninterruptible (woken explicitly). An uninterruptible sleep state is a sleep state that cannot handle a signal (such as waiting for disk or network IO (input/output)).
When the process is sleeping uninterruptibly, the signal will be noticed when the process returns from the system call or trap.
-- 這句是關鍵。 當處於uninterruptibly sleep 狀態時,只有當進程從system 調用返回時,才通知signal。
A process which ends up in 「D」 state for any measurable length of time is trapped in the midst of a system call (usually an I/O operation on a device — thus the initial in the ps output).
Such a process cannot be killed — it would risk leaving the kernel in an inconsistent state, leading to a panic. In general you can consider this to be a bug in the device driver that the process is accessing.
2.4 T(task_stopped or task_traced):暫停狀態或跟蹤狀態
向進程發送一個sigstop信號,它就會因響應該信號而進入task_stopped狀態(除非該進程自己處於 task_uninterruptible狀態而不響應信號)。(sigstop與sigkill信號同樣,是很是強制的。不容許用戶進程經過 signal系列的系統調用從新設置對應的信號處理函數。)
向進程發送一個sigcont信號,可讓其從task_stopped狀態恢復到task_running狀態。
當進程正在被跟蹤時,它處於task_traced這個特殊的狀態。「正在被跟蹤」指的是進程暫停下來,等待跟蹤它的進程對它進行操 做。好比在gdb中對被跟蹤的進程下一個斷點,進程在斷點處停下來的時候就處於task_traced狀態。而在其餘時候,被跟蹤的進程仍是處於前面提到 的那些狀態。
對於進程自己來講,task_stopped和task_traced狀態很相似,都是表示進程暫停下來。
而 task_traced狀態至關於在task_stopped之上多了一層保護,處於task_traced狀態的進程不能響應sigcont信號而被喚 醒。只能等到調試進程經過ptrace系統調用執行ptrace_cont、ptrace_detach等操做(經過ptrace系統調用的參數指定操 做),或調試進程退出,被調試的進程才能恢復task_running狀態。
2.5 Z (task_dead - exit_zombie):退出狀態,進程成爲殭屍進程
在Linux進程的狀態中,殭屍進程是很是特殊的一種,它是已經結束了的進程,可是沒有從進程表中刪除。太多了會致使進程表裏麪條目滿了,進而致使系統崩潰,卻是不佔用其餘系統資源。
它已經放棄了幾乎全部內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其餘進程收集,除此以外,殭屍進程再也不佔有任何內存空間。
進程在退出的過程當中,處於TASK_DEAD狀態。在這個退出過程當中,進程佔有的全部資源將被回收,除了task_struct結構(以及少數資源)之外。因而進程就只剩下task_struct這麼個空殼,故稱爲殭屍。
之因此保留task_struct,是由於task_struct裏面保存了進程的退出碼、以及一些統計信息。而其父進程極可能會關 心這些信息。好比在shell中,$?變量就保存了最後一個退出的前臺進程的退出碼,而這個退出碼每每被做爲if語句的判斷條件。
當 然,內核也能夠將這些信息保存在別的地方,而將task_struct結構釋放掉,以節省一些空間。可是使用task_struct結構更爲方便,由於在 內核中已經創建了從pid到task_struct查找關係,還有進程間的父子關係。釋放掉task_struct,則須要創建一些新的數據結構,以便讓 父進程找到它的子進程的退出信息。
子進程在退出的過程當中,內核會給其父進程發送一個信號,通知父進程來「收屍」。 父進程能夠經過wait系列的系統調用(如 wait四、waitid)來等待某個或某些子進程的退出,並獲取它的退出信息。而後wait系列的系統調用會順便將子進程的屍體 (task_struct)也釋放掉。
這個信號默認是SIGCHLD,可是在經過clone系統調用建立子進程時,能夠設置這個信號。
若是他的父進程沒安裝SIGCHLD信號處理函數調用wait或waitpid()等待子進程結束,又沒有顯式忽略該信號,那麼它就一直保持殭屍狀態,子進程的屍體(task_struct)也就沒法釋放掉。
若是這時父進程結束了,那麼init進程自動會接手這個子進程,爲它收屍,它仍是能被清除的。可是若是若是父進程是一個循環,不會結束,那麼子進程就會一直保持殭屍狀態,這就是爲何系統中有時會有不少的殭屍進程。
當進程退出的時候,會將它的全部子進程都託管給別的進程(使之成爲別的進程的子進程)。託管的進程多是退出進程所在進程組的下一個 進程(若是存在的話),或者是1號進程。因此每一個進程、每時每刻都有父進程存在。除非它是1號進程。1號進程,pid爲1的進程,又稱init進程。
linux系統啓動後,第一個被建立的用戶態進程就是init進程。它有兩項使命:
一、執行系統初始化腳本,建立一系列的進程(它們都是init進程的子孫);
二、在一個死循環中等待其子進程的退出事件,並調用waitid系統調用來完成「收屍」工做;
init進程不會被暫停、也不會被殺死(這是由內核來保證的)。它在等待子進程退出的過程當中處於task_interruptible狀態,「收屍」過程當中則處於task_running狀態。
Unix/Linux 處理殭屍進程的方法:
找出父進程號,而後kill 父進程,以後子進程(殭屍進程)會被託管到其餘進程,如init進程,而後由init進程將子進程的屍體(task_struct)釋放掉。
除了經過ps 的狀態來查看Zombi進程,還能夠用以下命令查看:
[oracle@rac1 ~]$ ps -ef|grep defun
oracle 13526 12825 0 16:48 pts/1 00:00:00 grep defun
oracle 28330 28275 0 May18 ? 00:00:00 [Xsession] <defunct>
殭屍進程解決辦法:
(1)改寫父進程,在子進程死後要爲它收屍。
具體作法是接管SIGCHLD信號。子進程死後,會發送SIGCHLD信號給父進程,父進程收到此信號後,執行 waitpid() 函數爲子進程收屍。這是基於這樣的原理:就算父進程沒有調用wait,內核也會向它發送SIGCHLD消息,儘管對的默認處理是忽略,若是想響應這個消 息,能夠設置一個處理函數。
(2)把父進程殺掉。
父進程死後,殭屍進程成爲"孤兒進程",過繼給1號進程init,init始終會負責清理殭屍進程.它產生的全部殭屍進程也跟着消失。如:
kill -9 `ps -ef | grep "Process Name" | awk '{ print $3 }'`
其中,「Process Name」爲處於zombie狀態的進程名。
(3)殺父進程不行的話,就嘗試用skill -t TTY關閉相應終端,TTY是進程相應的tty號(終端號)。可是,ps可能會查不到特定進程的tty號,這時就須要本身判斷了。
(4)重啓系統,這也是最經常使用到方法之一。
2.6 X (task_dead - exit_dead):退出狀態,進程即將被銷燬
進程在退出過程當中也可能不會保留它的task_struct。好比這個進程是多線程程序中被detach過的進程。或者父進程經過設 置sigchld信號的handler爲sig_ign,顯式的忽略了sigchld信號。(這是posix的規定,儘管子進程的退出信號能夠被設置爲 sigchld之外的其餘信號。)
此時,進程將被置於exit_dead退出狀態,這意味着接下來的代碼當即就會將該進程完全釋放。因此exit_dead狀態是很是短暫的,幾乎不可能經過ps命令捕捉到。
三. 進程狀態變化說明
3.1 進程的初始狀態
進程是經過fork系列的系統調用(fork、clone、vfork)來建立的,內核(或內核模塊)也能夠經過 kernel_thread函數建立內核進程。這些建立子進程的函數本質上都完成了相同的功能——將調用進程複製一份,獲得子進程。(能夠經過選項參數來 決定各類資源是共享、仍是私有。)
那麼既然調用進程處於task_running狀態(不然,它若不是正在運行,又怎麼進行調用?),則子進程默認也處於task_running狀態。
另外,在系統調用調用clone和內核函數kernel_thread也接受clone_stopped選項,從而將子進程的初始狀態置爲 task_stopped。
3.2 進程狀態變遷
進程自建立之後,狀態可能發生一系列的變化,直到進程退出。而儘管進程狀態有好幾種,可是進程狀態的變遷卻只有兩個方向——從 task_running狀態變爲非task_running狀態、或者從非task_running狀態變爲task_running狀態。
也 就是說,若是給一個task_interruptible狀態的進程發送sigkill信號,這個進程將先被喚醒(進入task_running狀態), 而後再響應sigkill信號而退出(變爲task_dead狀態)。並不會從task_interruptible狀態直接退出。
進程從非task_running狀態變爲task_running狀態,是由別的進程(也多是中斷處理程序)執行喚醒操做來實現 的。執行喚醒的進程設置被喚醒進程的狀態爲task_running,而後將其task_struct結構加入到某個cpu的可執行隊列中。因而被喚醒的 進程將有機會被調度執行。
而進程從task_running狀態變爲非task_running狀態,則有兩種途徑: 一、響應信號而進入task_stoped狀態、或task_dead狀態; 二、 執行系統調用主動進入task_interruptible狀態(如nanosleep系統調用)、或task_dead狀態(如exit系統調用);或 因爲執行系統調用須要的資源得不到知足,而進入task_interruptible狀態或task_uninterruptible狀態(如 select系統調用)。顯然,這兩種狀況都只能發生在進程正在cpu上執行的狀況下。