CentOS進程狀態講解

來源:互聯網
上載者:User

CentOS進程狀態講解

Linux是一個多使用者,多任務的系統,可以同時運行多個使用者的多個程式,就必然會產生很多的進程,而每個進程會有不同的狀態。在下文將對進程的

R、S、D、T、Z、X六種狀態做個說明。

PROCESS STATE CODES

Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display to describe the state of a process.

DUninterruptible sleep(usually IO)

RRunning or runnable (on run queue)

SInterruptible sleep(waiting for an event to complete)

TStopped, either by a job control signal or because it is being traced.

Wpaging (not valid since the 2.6.xx kernel)

Xdead (should never be seen)

ZDefunct ("zombie") process, terminated but not

reaped by its parent.

For BSD formats and when the stat keyword is used,additional characters may be displayed:

<high-priority (not nice to other users)

Nlow-priority (nice to other users)

Lhas pages locked into memory (for real-time and custom IO)

sis a session leader

lis multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

+is in the foreground process group

一.查看進程的狀態

1.1使用PS命令

[root@localhost]#ps -a -o pid,ppid,stat,command -u oracle

PIDPPID STAT COMMAND

6371 SsoracleXEZF (LOCAL=NO)

7291 SsoracleXEZF (LOCAL=NO)

11441103 S+top

12301 SsoracleXEZF (LOCAL=NO)

12891145 S+vmstat 10

16991 SsoracleXEZF (LOCAL=NO)

18271294 R+ps -a -o pid,ppid,stat,command -u oracle

34101 Ssora_pmon_XEZF

34121 Ssora_psp0_XEZF

34141 Ssora_mman_XEZF

34161 Ssora_dbw0_XEZF

34181 Ssora_lgwr_XEZF

34201 Ssora_ckpt_XEZF

34221 Ssora_smon_XEZF

34241 Ssora_reco_XEZF

34261 Ssora_mmon_XEZF

34281 Ssora_mmnl_XEZF

34301 Ssora_d000_XEZF

34321 Ssora_d001_XEZF

34341 Ssora_s000_XEZF

34361 Ssora_s001_XEZF

34381 Ssora_s002_XEZF

34881 Ssl/home/oracle_app/bin/tnslsnr LISTENER -inherit

111671 SsoracleXEZF (LOCAL=NO)

114231 SsoracleXEZF (LOCAL=NO)

114251 SsoracleXEZF (LOCAL=NO)

114291 SsoracleXEZF (LOCAL=NO)

148671 SsoracleXEZF (LOCAL=NO)

193231 SsoracleXEZF (LOCAL=NO)

用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 userprnivirtresshrs%cpu %memtime+command

11423 oracle160627m 170m 168mR329.04110:21 oracle

3416 oracle150650m 158m 138mS08.40:07.12 oracle

11167 oracle150626m 151m 149mS08.0 400:20.77 oracle

11429 oracle150626m 148m 147mS07.9 812:05.71 oracle

3422 oracle180627m 140m 137mS07.41:12.23 oracle

1230 oracle150639m 107m96mS05.70:10.00 oracle

637 oracle150629m76m73mS04.00:04.31 oracle

二.進程狀態說明

2.1R (task_running) :可執行狀態

只有在該狀態的進程才可能在CPU上運行。而同一時刻可能有多個進程處於可執行狀態,這些進程的task_struct結構(進程式控制制塊)被放入對應CPU的可執行隊列中(一個進程最多隻能出現在一個CPU的可執行隊列中)。進程調度器的任務就是從各個CPU的可執行隊列中分別選擇一個進程在該CPU上運行。

很多作業系統教科書將正在CPU上執行的進程定義為RUNNING狀態、而將可執行但是尚未被調度執行的進程定義為READY狀態,這兩種狀態在linux下統一為TASK_RUNNING狀態。

2.2S (task_interruptible):可中斷的睡眠狀態

處於這個狀態的進程因為等待某某事件的發生(比如等待socket串連、等待訊號量),而被掛起。這些進程的task_struct結構被放入對應事件的等待隊列中。當這些事件發生時(由外部中斷觸發、或由其他進程觸發),對應的等待隊列中的一個或多個進程將被喚醒。

通過ps命令我們會看到,一般情況下,進程列表中的絕大多數進程都處於task_interruptible狀態(除非機器的負載很高)。畢竟CPU就這麼一兩個,進程動輒幾十上百個,如果不是絕大多數進程都在睡眠,CPU又怎麼響應得過來。

2.3D (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.4T(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系列的系統調用(如wait4、waitid)來等待某個或某些子進程的退出,並擷取它的退出資訊。然後wait系列的系統調用會順便將子進程的屍體(task_struct)也釋放掉。

這個訊號預設是SIGCHLD,但是在通過clone系統調用建立子進程時,可以設定這個訊號。

如果他的父進程沒安裝SIGCHLD訊號處理函數調用wait或waitpid()等待子進程結束,又沒有顯式忽略該訊號,那麼它就一直保持殭屍狀態,子進程的屍體(task_struct)也就無法釋放掉。

如果這時父進程結束了,那麼init進程自動會接手這個子進程,為它收屍,它還是能被清除的。但是如果如果父進程是一個迴圈,不會結束,那麼子進程就會一直保持殭屍狀態,這就是為什麼系統中有時會有很多的殭屍進程。

當進程退出的時候,會將它的所有子進程都託管給別的進程(使之成為別的進程的子進程)。託管的進程可能是退出進程所在進程組的下一個進程(如果存在的話),或者是1號進程。所以每個進程、每時每刻都有父進程存在。除非它是1號進程。1號進程,pid為1的進程,又稱init進程。


linux系統啟動後,第一個被建立的使用者態進程就是init進程。它有兩項使命:
1、執行系統初始化指令碼,建立一系列的進程(它們都是init進程的子孫);
2、在一個死迴圈中等待其子進程的退出事件,並調用waitid系統調用來完成“收屍”工作;

init進程不會被暫停、也不會被殺死(這是由核心來保證的)。它在等待子進程退出的過程中處於task_interruptible狀態,“收屍”過程中則處於task_running狀態。

Unix/Linux處理殭屍進程的方法:

找出父進程號,然後kill父進程,之後子進程(殭屍進程)會被託管到其他進程,如init進程,然後由init進程將子進程的屍體(task_struct)釋放掉。

除了通過ps的狀態來查看Zombi進程,還可以用如下命令查看:

[oracle@rac1 ~]$ ps -ef|grep defun

oracle13526 128250 16:48 pts/100:00:00 grep defun

oracle28330 282750 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狀態,則有兩種途徑:
1、響應訊號而進入task_stoped狀態、或task_dead狀態;
2、執行系統調用主動進入task_interruptible狀態(如nanosleep系統調用)、或task_dead狀態(如exit系統調用);或由於執行系統調用需要的資源得不到滿足,而進入task_interruptible狀態或task_uninterruptible狀態(如select系統調用)。
顯然,這兩種情況都只能發生在進程正在cpu上執行的情況下。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.