RDSTWXZ 狀態

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

RSDTZ六種狀態做個說明。

 

PROCESS STATE CODES

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

       D    Uninterruptiblesleep (usually IO)

       R    Runningor runnable (on run queue)

       S    Interruptiblesleep (waiting for an event to complete)

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

       W    paging(not valid since the 2.6.xx kernel)

       X    dead(should never be seen)

       Z    Defunct("zombie") process, terminated but not

            reapedby its parent.

 

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

       <    high-priority(not nice to other users)

       N    low-priority(nice to other users)

       L    haspages locked into memory (for real-time and custom IO)

       s    isa session leader

       l    ismulti-threaded (using CLONE_THREAD, like NPTL pthreads do)

       +    is in the foreground process group

查看進程的狀態

1.1 使用PS命令

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

  PID  PPID STAT COMMAND

  637     1Ss   oracleXEZF (LOCAL=NO)

  729     1Ss   oracleXEZF (LOCAL=NO)

 1144  1103 S+   top

 1230     1Ss   oracleXEZF (LOCAL=NO)

 1289  1145 S+   vmstat 10

 1699     1Ss   oracleXEZF (LOCAL=NO)

 1827  1294 R+   ps -a -opid,ppid,stat,command -u oracle

 3410     1Ss   ora_pmon_XEZF

 3412     1Ss   ora_psp0_XEZF

 3414     1Ss   ora_mman_XEZF

 3416     1Ss   ora_dbw0_XEZF

 3488     1 Ssl /home/oracle_app/bin/tnslsnr LISTENER -inherit

11167     1Ss   oracleXEZF (LOCAL=NO)

19323     1Ss   oracleXEZF (LOCAL=NO)

 

ps 的 –選項,得 到更詳細的進程信息:

1F(Flag):一系列數字的和,表示進程的當前狀態。這些數字的含義爲: 

       00:若單獨顯示,表示此進程已被終止。 

       01:進程是核心進程的一部分,常駐於系統主存。如:schedvhandbdflush 

       02Parent 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:等待運行(runableR Running or runnable (on runqueue) 進程處於運行或就緒狀態

       I:空閒狀態(idle 

       Z:殭屍狀態(zombie)    

       T:跟蹤狀態(Traced 

       B:進程正在等待更多的內存頁 

       D:不可中斷的深度睡眠,一般由IO引起,同步IO在做讀或寫操作時,cpu不能做其它事情,只能等待,這時進程處於這種狀態,如果程序採用異步IO,這種狀態應該就很少見到了

3C(cpuusage)cpu利 用率的估算值

1.2 使用Top命令中的字段

piduser      pr  ni  virt  res  shrs %cpu%mem    time+  command                                

11423oracle    16   0  627m170m168mR   32  9.0   4110:21oracle                                 

 3416oracle    15   0  650m158m138mS    0  8.4   0:07.12oracle                                                           

  637oracle    15   0  629m  76m  73mS    0  4.0   0:04.31oracle                    

.  進程狀態說明

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狀態的進程,無論是”killkill -9″還是”kill -15″,這種情況下,一個可選的方法就是reboot

       處於uninterruptible sleep狀態的進程通常是在等待IO,比如磁盤IO,網絡IO,其他外設IO,如果進程正在等待的IO在較長的時間內都沒有響應,那麼就被ps看到了,同時也就意味着很有可能有IO出了問題,可能是外設本身出了故障,也可能是比如掛載的遠程文件系統已經不可訪問了.

       task_uninterruptible狀態存在的意義就在於,內核的某些處理流程是不能被打斷的。如果響應異步信號,程序的執行流程中就會被插入一段用於處理異步信號的流程(這個插入的流程可能只存在於內核態,也可能延伸到用戶態),於是原有的流程就被中斷了。

       在進程對某些硬件進行操作時(比如進程調用read系統調用對某個設 備文件進行讀操作,而read系統調用最終執行到對應設備驅動的代碼,並與對應的物理設備進行交互),可能需要使用task_uninterruptible狀態對進程進行保護,以避免進程與設備交互的過程被打斷,造成設備陷入不可控的狀態。這種情況下的task_uninterruptible狀態總是非常短暫的,通過ps命 令基本上不可能捕捉到。

       我們通過vmstat 命令中procs下的可以來查看是否有處於uninterruptible 狀態的進程。該命令只能顯示數量。

       In computeroperating 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 cannothandle a signal (such as waiting for disk or network IO (input/output)).

       When the process is sleeping uninterruptibly, the signal willbe noticed when the process returns from the system call or trap.

       -- 這句是關鍵。 當處於uninterruptiblysleep 狀態時,只有當進程從system 調用返回時,才通知signal

       A process whichends up in D state for anymeasurable length of time is trapped in the midst of a system call (usually anI/O operation on a device  thus the initial in the psoutput).

       Such a process cannot be killed  it would risk leaving the kernel in an inconsistent state, leadingto a panic. In general you can consider this to be abug in the device driver that the process is accessing.

2.4  T(task_stoppedor task_traced):暫停狀態或跟蹤狀態

       向進程發送一個sigstop信號,它就會因響應該信號而進入task_stopped狀態(除非該進程本身處於task_uninterruptible狀態而不響應信號)。(sigstopsigkill信號一樣,是非常強制的。不允許用戶進程通過signal系列的系統調用重新設置對應的信號處理函數。)
       
向進程發送一個sigcont信號,可以讓其從task_stopped狀態恢復到task_running狀態。

       當進程正在被跟蹤時,它處於task_traced這個特殊的狀態。“正 在被跟蹤”指的是進程暫停下來,等待跟蹤它的進程對它進行操作。比如在gdb中對被跟蹤的進程下一個斷點,進程在斷點處停下來的時候就處於task_traced狀態。而在其他時候,被跟蹤的進程還是處於前面提到的那些狀態。     

       對於進程本身來說,task_stoppedtask_traced狀態很類似,都是表示進程暫停下來。
       
task_traced狀態相當於在task_stopped之上多了一層保護,處於task_traced狀態的進程不能響應sigcont信號而被喚醒。只能等到調試進程通過ptrace系統調用執行ptrace_contptrace_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結構更爲方便,因爲在內核中已經建立了從pidtask_struct查找關係,還有進程間的父子關係。釋放掉task_struct,則需要建立一些新的數據結構,以便讓父進程找到它的子進程的退出信息。

       子進程在退出的過程中,內核會給其父進程發送一個信號,通知父進程來“收 屍”。父進程可以通過wait系列的系統調用(如wait4waitid)來等待某個或某些子進程的退出,並獲取它的退出信息。然後wait系列的系統調用會順便將子進程的屍體(task_struct)也釋放掉。

       這 個信號默認是SIGCHLD但是在通過clone系統調用創建 子進程時,可以設置這個信號。

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

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

       當進程退出的時候,會將它的所有子進程都託管給別的進程(使之成爲別的進程的子進程)。託管的進程可能是退出進程所在進程組的下一個進程(如果存在的話),或者是1號進程。所以每個進程、每時每刻都有父進程 存在。除非它是1號進程。1號進程,pid1的進程,又稱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

oracle   13526 12825  0 16:48 pts/1    00:00:00 grepdefun

oracle   2833028275  0 May18?        00:00:00 [Xsession]<defunct>

殭屍進程解決辦 法:

1)改寫父進程,在子進程死後要爲它收屍。

       具體做法是接管SIGCHLD信號。子進程死後,會發送SIGCHLD信號給父進程,父進程收到此信號後,執行 waitpid()函數爲子進程收屍。這是基於這樣的原理:就算父進程沒有調用wait,內核也會向它發送SIGCHLD消息,儘管對的默認處理是忽略,如果想響應這個消息,可以設置一個處理函數。

2)把父進程殺掉。

       父進程死後,殭屍進程成爲"孤兒進程",過繼給1號進程initinit始終會負責清理殭屍進程.它產生的所有殭屍進程也跟着消失。如:

       kill -9 `ps -ef |grep "Process Name" | awk '{ print $3 }'`
       
其中,“ProcessName”爲處於zombie狀態的進程名。

3)殺父進程不行的話,就嘗試用skill -t TTY關閉相應終端,TTY是進程相應的tty(終 端號)但是,ps可能會查不到特定進程的tty號,這時就需要自己判斷了。
4)重啓系統,這也是最常用到方法之一。

2.6 X (task_dead -exit_dead):退出狀態,進程即將被銷燬

       進程在退出過程中也可能不會保留它的task_struct。比如這個進程是多線程程序中被detach過的進 程。或者父進程通過設置sigchld信號的handlersig_ign,顯式的忽略了sigchld信號。(這是posix的規定,儘管子進程的退出信號可以被設置爲sigchld以外的其他信號。)
       
此時,進程將被置於exit_dead退出狀態,這意味着接下來的代碼立即就會將該進程徹底釋放。所以exit_dead狀態是非常短暫的,幾乎不可能通過ps命 令捕捉到。

 

進程狀態變化說明

3.1 進程的初始狀態

       進程是通過fork系列的系統調用(forkclonevfork)來創建的,內核(或內核模塊)也可以通過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上執行的情況下。

 

 

 

狀態的進程

http://hi.baidu.com/xuwanbest/blog/item/45f18f3dbce0aece9e3d6255.html

ps 的手冊裏說D狀態是uninterruptible sleep,Linux進程有兩種睡眠狀態,一種interruptible sleep,處在這種睡眠狀態的進程是可以通過給它發信號來喚醒的,比如發HUP信號給nginx的master進程可以讓nginx重新加載配置文件而 不需要重新啓動nginx進程;另外一種睡眠狀態是uninterruptible sleep,處在這種狀態的進程不接受外來的任何信號,這也是爲什麼之前我無法用kill殺掉這些處於D狀態的進程,無論是”kill”, “kill -9″還是”kill -15″,因爲它們壓根兒就不受這些信號的支配。

進程爲什麼會被置於uninterruptible sleep狀態呢?處於uninterruptible sleep狀態的進程通常是在等待IO,比如磁盤IO,網絡IO,其他外設IO,如果進程正在等待的IO在較長的時間內都沒有響應,那麼就很會不幸地被 ps看到了,同時也就意味着很有可能有IO出了問題,可能是外設本身出了故障,也可能是比如掛載的遠程文件系統已經不可訪問了。

正是因爲得不到IO的相應,進程才進入了uninterruptible sleep狀態,所以要想使進程從uninterruptible sleep狀態恢復,就得使進程等待的IO恢復,比如如果是因爲從遠程掛載的NFS卷不可訪問導致進程進入uninterruptible sleep狀態的,那麼可以通過恢復該NFS卷的連接來使進程的IO請求得到滿足,除此之外,要想幹掉處在D狀態進程就只能重啓整個Linux系統了。

看到有人說如果要想殺掉D狀態的進程,通常可以去殺掉它的父進程(通常是shell,我理解的這種情況是在shell下直接運行的該進程,之後該進 程轉入了D狀態),於是我就照做了,之後就出現了上面的狀態:他們的父進程被殺掉了,但是他們的父進程PID都變成了1,也就是init進程,這下可如何 是好?此時我這些D狀態的進程已經影響到其他一些進程的運行,而已經無法訪問的NFS卷又在段時間內無法恢復,那麼,只好重新啓動了,root不是玉皇大 帝,也有無奈的時候。

czhang說起這個事,覺得Linux如果有這麼一個專用的垃圾回收進程就好了:系統自動或者用戶手動把殭屍進程,和比如之前我遇到的D狀態進程的PPID設爲這個垃圾回收進程,那麼通過幹掉這個垃圾回收進程來清理這些殭屍們,這樣該有多美好…

發佈了0 篇原創文章 · 獲贊 7 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章