Linux 进程状态【转】
轉自:http://www.cnblogs.com/itech/p/3208261.html
來自:?http://blog.csdn.net/tianlesoftware/article/details/6457487
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.
???????D????Uninterruptible sleep?(usually IO)
???????R????Running or runnable (on run queue)
???????S????Interruptible sleep?(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
????????????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)
???????N????low-priority (nice to other users)
???????L????has pages locked into memory (for real-time and custom IO)
???????s????is a session leader
???????l????is 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
??PID??PPID STAT COMMAND
??637?????1 Ss???oracleXEZF (LOCAL=NO)
??729?????1 Ss???oracleXEZF (LOCAL=NO)
?1144??1103 S+???top
?1230?????1 Ss???oracleXEZF (LOCAL=NO)
?1289??1145 S+???vmstat 10
?1699?????1 Ss???oracleXEZF (LOCAL=NO)
?1827??1294 R+???ps -a -o pid,ppid,stat,command -u oracle
?3410?????1 Ss???ora_pmon_XEZF
?3412?????1 Ss???ora_psp0_XEZF
?3414?????1 Ss???ora_mman_XEZF
?3416?????1 Ss???ora_dbw0_XEZF
?3418?????1 Ss???ora_lgwr_XEZF
?3420?????1 Ss???ora_ckpt_XEZF
?3422?????1 Ss???ora_smon_XEZF
?3424?????1 Ss???ora_reco_XEZF
?3426?????1 Ss???ora_mmon_XEZF
?3428?????1 Ss???ora_mmnl_XEZF
?3430?????1 Ss???ora_d000_XEZF
?3432?????1 Ss???ora_d001_XEZF
?3434?????1 Ss???ora_s000_XEZF
?3436?????1 Ss???ora_s001_XEZF
?3438?????1 Ss???ora_s002_XEZF
?3488?????1 Ssl??/home/oracle_app/bin/tnslsnr LISTENER -inherit
11167?????1 Ss???oracleXEZF (LOCAL=NO)
11423?????1 Ss???oracleXEZF (LOCAL=NO)
11425?????1 Ss???oracleXEZF (LOCAL=NO)
11429?????1 Ss???oracleXEZF (LOCAL=NO)
14867?????1 Ss???oracleXEZF (LOCAL=NO)
19323?????1 Ss???oracleXEZF (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 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系列的系統調用(如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
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狀態,則有兩種途徑:
???????1、響應信號而進入task_stoped狀態、或task_dead狀態;
???????2、執行系統調用主動進入task_interruptible狀態(如nanosleep系統調用)、或task_dead狀態(如exit系統調用);或由于執行系統調用需要的資源得不到滿足,而進入task_interruptible狀態或task_uninterruptible狀態(如select系統調用)。
顯然,這兩種情況都只能發生在進程正在cpu上執行的情況下。
作者:iTech
出處:http://itech.cnblogs.com/?
轉載于:https://www.cnblogs.com/sky-heaven/p/5730001.html
總結
以上是生活随笔為你收集整理的Linux 进程状态【转】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MyBatis学习总结(16)——Myb
- 下一篇: Linux系统的中断、系统调用和调度概述