Linux進(jìn)程狀態(tài)和優(yōu)先級(jí)的用法及說(shuō)明
1. OS教材中的進(jìn)程狀態(tài)
首先我們要知道,系統(tǒng)中的進(jìn)程有三個(gè)最基本也是最重要的狀態(tài):運(yùn)行、阻塞、掛起。
然后要介紹一個(gè)概念,調(diào)度隊(duì)列。
1.1 調(diào)度隊(duì)列和等待隊(duì)列
操作系統(tǒng)會(huì)為 CPU 提供一個(gè)調(diào)度隊(duì)列,它是操作系統(tǒng)內(nèi)核用于管理進(jìn)程調(diào)度的核心隊(duì)列結(jié)構(gòu),1里面存放的是所有已經(jīng)具備運(yùn)行條件、等待 CPU 分配時(shí)間片的進(jìn)程。

大概邏輯就是這樣。
在我們學(xué)校當(dāng)中的教材里面,絕大部分會(huì)將就緒態(tài)和運(yùn)行態(tài)嚴(yán)格區(qū)分開(kāi)來(lái),教材中認(rèn)為,就緒狀態(tài)是指進(jìn)程已經(jīng)獲得除 CPU 以外的所有所需資源,完成了運(yùn)行前的全部準(zhǔn)備工作,只等待操作系統(tǒng)調(diào)度器分配 CPU 時(shí)間片即可立即執(zhí)行的狀態(tài)。
處于就緒狀態(tài)的進(jìn)程會(huì)被 操作系統(tǒng)放入調(diào)度隊(duì)列中,由調(diào)度器按照調(diào)度策略依次選擇上 CPU 運(yùn)行。它與正在 CPU 上執(zhí)行的運(yùn)行狀態(tài)的唯一區(qū)別,就是當(dāng)前是否占用 CPU;一旦調(diào)度器切換 CPU 使用權(quán)給該進(jìn)程,它就從就緒狀態(tài)變?yōu)檫\(yùn)行狀態(tài);如果時(shí)間片用完被換下 CPU,它又回到就緒狀態(tài)繼續(xù)排隊(duì)。
1.2 阻塞和運(yùn)行狀態(tài)
但是在實(shí)際的Linux 操作系統(tǒng)中,只要進(jìn)程位于 CPU 的調(diào)度隊(duì)列中,內(nèi)核就統(tǒng)一將其標(biāo)記為 TASK_RUNNING 狀態(tài),也就是我們常說(shuō)的運(yùn)行狀態(tài)。這里的 “運(yùn)行狀態(tài)” 包含兩層含義:一種是進(jìn)程正在 CPU 上真實(shí)執(zhí)行指令,另一種是進(jìn)程已準(zhǔn)備就緒、在調(diào)度隊(duì)列中等待被調(diào)度器選中執(zhí)行。操作系統(tǒng)并不單獨(dú)區(qū)分 “就緒隊(duì)列” 和 “運(yùn)行隊(duì)列”,凡是在調(diào)度隊(duì)列中、具備執(zhí)行條件的進(jìn)程,都屬于運(yùn)行狀態(tài),調(diào)度器會(huì)按照調(diào)度算法從隊(duì)列中依次挑選進(jìn)程上 CPU 運(yùn)行。
所以,我們就記?。?strong>進(jìn)程在調(diào)度隊(duì)列里,就可以認(rèn)定它處于運(yùn)行狀態(tài)。
就緒狀態(tài)和運(yùn)行狀態(tài)大概了解了,接下來(lái)我們講一講阻塞狀態(tài)。為了能更好的讓大家理解,我們先看一看進(jìn)程處于阻塞狀態(tài)的現(xiàn)象:

對(duì)于上圖中這個(gè)代碼,我們因?yàn)閷?xiě)了一個(gè)scanf,所以需要我們先從鍵盤(pán)上寫(xiě)入內(nèi)容,然后再讀取才能繼續(xù)運(yùn)行。同時(shí)我們查看進(jìn)程,可以看到這個(gè)myprocess可執(zhí)行程序是一個(gè)正在運(yùn)行的進(jìn)程,所以這種一個(gè)進(jìn)程卡住不動(dòng)的現(xiàn)象,就叫做阻塞。
這是從看到的現(xiàn)象中去理解阻塞的意義,那么接下來(lái)我們從操作系統(tǒng)的角度再去理解。
首先,我們寫(xiě)下scanf函數(shù)并執(zhí)行之后,我們計(jì)算機(jī)中的操作系統(tǒng)就在等待鍵盤(pán)上能輸入數(shù)據(jù)。而這個(gè)鍵盤(pán)屬于是硬件設(shè)備,一旦鍵盤(pán)輸入數(shù)據(jù),就表示鍵盤(pán)數(shù)據(jù)就緒,即硬件就緒。
操作系統(tǒng)作為硬件的管理者,管理的方式還是我們之前講過(guò)的:先描述,再組織。所以對(duì)于硬件來(lái)說(shuō),它也有對(duì)應(yīng)的類(lèi)似于 struct task_struct 一樣的屬性信息結(jié)構(gòu)體。并且因?yàn)橛布恢挂粋€(gè),所以有 struct device *next 給鏈接起來(lái),和我們?cè)谏掀恼轮刑岬降牟僮飨到y(tǒng)底層的信息管理邏輯一樣。同時(shí)還存在一個(gè)指向進(jìn)程描述符類(lèi)型的指針 :struct task_struct *wait_queue。

當(dāng)我們要運(yùn)行這個(gè)代碼的時(shí)候:

一遇到scanf,操作系統(tǒng)就會(huì)去向鍵盤(pán)要數(shù)據(jù),但是因?yàn)橛脩?hù)還沒(méi)有通過(guò)鍵盤(pán)輸入數(shù)據(jù),所以就表示硬盤(pán)未就緒,此時(shí)就相當(dāng)于該進(jìn)程正在等待,那么此時(shí),操作系統(tǒng)就會(huì)把調(diào)度隊(duì)列中的我們本來(lái)要運(yùn)行的這個(gè)進(jìn)程拿出來(lái),將這個(gè)進(jìn)程的PCB中的運(yùn)行狀態(tài)改為阻塞狀態(tài),再放到鍵盤(pán)設(shè)備對(duì)應(yīng)的等待隊(duì)列里。此時(shí)因?yàn)檫M(jìn)程現(xiàn)在已經(jīng)不在調(diào)度隊(duì)列里了,那就不再參與 CPU 調(diào)度,所以才會(huì)出現(xiàn)“卡住”的樣子,直到所等待的事件發(fā)生,內(nèi)核才會(huì)將進(jìn)程從等待隊(duì)列中取下,重新放回調(diào)度隊(duì)列,使其恢復(fù)運(yùn)行狀態(tài):

因此我們可以做一個(gè)總結(jié):阻塞和運(yùn)行的本質(zhì)區(qū)別,實(shí)際上就是看你這個(gè)進(jìn)程的task_struct在誰(shuí)提供的隊(duì)列當(dāng)中。
1.3掛起狀態(tài)
接著我們來(lái)談一談什么叫做掛起。

在操作系統(tǒng)同時(shí)運(yùn)行大量進(jìn)程的場(chǎng)景下,若系統(tǒng)檢測(cè)到物理內(nèi)存資源不足,為了優(yōu)化內(nèi)存使用、保證關(guān)鍵進(jìn)程正常運(yùn)行,操作系統(tǒng)會(huì)選擇一部分優(yōu)先級(jí)較低、暫時(shí)不急需執(zhí)行的進(jìn)程,將其數(shù)據(jù)與代碼遷移到其他存儲(chǔ)空間,再釋放該進(jìn)程占用的內(nèi)存。在硬件層面,磁盤(pán)上專(zhuān)門(mén)用于此類(lèi)臨時(shí)存儲(chǔ)的區(qū)域稱(chēng)為 swap 交換分區(qū),它的作用就是存放這些暫時(shí)不緊急的進(jìn)程數(shù)據(jù)。
那么如何判斷哪些進(jìn)程屬于 “不緊急、可遷移” 的對(duì)象呢?操作系統(tǒng)通常優(yōu)先選擇處于阻塞狀態(tài)的進(jìn)程。因?yàn)樽枞M(jìn)程正在等待某一事件(如 I/O 完成、鍵盤(pán)輸入、資源釋放等),短期內(nèi)無(wú)法投入運(yùn)行。系統(tǒng)會(huì)將這類(lèi)進(jìn)程的代碼、數(shù)據(jù)等從內(nèi)存換出,保存到 swap 分區(qū),然后釋放內(nèi)存空間,供其他更活躍、更急需的進(jìn)程使用。
當(dāng)阻塞進(jìn)程等待的事件就緒、需要繼續(xù)執(zhí)行時(shí),操作系統(tǒng)會(huì)將其數(shù)據(jù)從 swap 分區(qū)重新加載回內(nèi)存,使進(jìn)程恢復(fù)可調(diào)度狀態(tài),再將其放入調(diào)度隊(duì)列,等待 CPU 調(diào)度執(zhí)行。
因此,掛起狀態(tài)可以這樣定義:當(dāng) “進(jìn)程的代碼、數(shù)據(jù)等內(nèi)容被暫時(shí)換出內(nèi)存、保存到磁盤(pán)的 swap 分區(qū),僅在內(nèi)存中保留進(jìn)程控制塊 task_struct 以標(biāo)識(shí)進(jìn)程存在” 時(shí),該進(jìn)程所處的狀態(tài)即為掛起狀態(tài)。處于掛起狀態(tài)的進(jìn)程既不占用實(shí)際內(nèi)存空間,也不參與 CPU 調(diào)度,必須先被重新調(diào)入內(nèi)存,才能繼續(xù)等待事件或參與調(diào)度。
其中,如果進(jìn)程原本處于阻塞狀態(tài),在內(nèi)存不足時(shí)被 操作系統(tǒng)換出到 swap 分區(qū),進(jìn)入掛起,這叫做阻塞掛起;如果進(jìn)程原本已經(jīng)具備運(yùn)行條件,在調(diào)度隊(duì)列當(dāng)中,處于運(yùn)行狀態(tài),只是因?yàn)閮?nèi)存緊張而被換出到 swap 分區(qū)(這種是因?yàn)橐呀?jīng)將阻塞狀態(tài)的進(jìn)程的數(shù)據(jù)放到swap分區(qū)后,內(nèi)存空間依然不足),那就叫做運(yùn)行掛起。
關(guān)于 swap 交換分區(qū)我們還需要再詳細(xì)介紹一下:
它是操作系統(tǒng)在磁盤(pán)上劃分的一塊專(zhuān)用存儲(chǔ)空間,主要用作虛擬內(nèi)存,用來(lái)緩解物理內(nèi)存不足的問(wèn)題,其空間大小一般為 內(nèi)存空間大小的 1~2 倍。當(dāng)系統(tǒng)同時(shí)運(yùn)行大量進(jìn)程,導(dǎo)致物理內(nèi)存資源緊張時(shí),內(nèi)核會(huì)將部分暫時(shí)不活躍的進(jìn)程數(shù)據(jù)從內(nèi)存轉(zhuǎn)移到 Swap 分區(qū),從而騰出寶貴的物理內(nèi)存供當(dāng)前急需運(yùn)行的程序使用。因此,Swap 本質(zhì)上是用磁盤(pán)空間擴(kuò)展內(nèi)存容量的一種機(jī)制。
將數(shù)據(jù)從內(nèi)存寫(xiě)入 Swap 分區(qū)的過(guò)程,稱(chēng)為 swap out。當(dāng)掛起進(jìn)程等待的事件就緒、需要繼續(xù)執(zhí)行時(shí),操作系統(tǒng)會(huì)將之前存放在 Swap 分區(qū)中的代碼和數(shù)據(jù)重新讀回物理內(nèi)存,并恢復(fù)其運(yùn)行環(huán)境。這個(gè)從 Swap 分區(qū)讀回內(nèi)存的過(guò)程,稱(chēng)為 swap in。
簡(jiǎn)單來(lái)說(shuō),Swap 分區(qū)相當(dāng)于內(nèi)存的 “后備倉(cāng)庫(kù)”,swap out 負(fù)責(zé)騰出內(nèi)存,swap in 負(fù)責(zé)恢復(fù)進(jìn)程運(yùn)行。借助這一機(jī)制,操作系統(tǒng)既可以在內(nèi)存緊張時(shí)保證系統(tǒng)穩(wěn)定運(yùn)行,又能實(shí)現(xiàn)進(jìn)程掛起與喚醒,提升整體資源利用率。不過(guò),swap交換分區(qū)也有一個(gè)缺點(diǎn),因?yàn)?Swap 在磁盤(pán)上,速度遠(yuǎn)慢于內(nèi)存,頻繁 swap 會(huì)導(dǎo)致系統(tǒng)卡頓。
2. 具體OS中的狀態(tài)
我們上面提到的阻塞、運(yùn)行、掛起,都只是在簡(jiǎn)單介紹它們的概念,僅僅停留在基礎(chǔ)知識(shí),屬于是通用操作系統(tǒng)理論。但是在實(shí)際的Linux操作系統(tǒng)當(dāng)中,這三種狀態(tài)都是怎么被標(biāo)識(shí)的,到底長(zhǎng)什么樣子,我們還不了解。
/*
*The task state array is a strange "bitmap" of
*reasons to sleep. Thus "running" is zero, and
*you can test for combinations of others with
*simple bit tests.
*/
static const char *const task_state_array[] =
{
"R (running)", /*0 */
"S (sleeping)", /*1 */
"D (disk sleep)", /*2 */
"T (stopped)", /*4 */
"t (tracing stop)", /*8 */
"X (dead)", /*16 */
"Z (zombie)", /*32 */
};這是Linux操作系統(tǒng)中關(guān)于進(jìn)程狀態(tài)的數(shù)組,里面存儲(chǔ)了進(jìn)程的不同狀態(tài)。
- R 運(yùn)行狀態(tài)(running): 并不意味著進(jìn)程一定在運(yùn)行中,它表明進(jìn)程要么是在運(yùn)行中要么在運(yùn)行隊(duì)列里。
- S 睡眠狀態(tài)(sleeping): 意味著進(jìn)程在等待事件完成(這里的睡眠有時(shí)候也叫做可中斷睡眠(interruptible sleep))。
- D 磁盤(pán)休眠狀態(tài)(Disk sleep)有時(shí)候也叫不可中斷睡眠狀態(tài)(uninterruptible sleep),在這個(gè)狀態(tài)的進(jìn)程通常會(huì)等待 IO 的結(jié)束。
- T 停止?fàn)顟B(tài)(stopped): 可以通過(guò)發(fā)送 SIGSTOP 信號(hào)給進(jìn)程來(lái)停止(T)進(jìn)程。這個(gè)被暫停的進(jìn)程可以通過(guò)發(fā)送 SIGCONT 信號(hào)讓進(jìn)程繼續(xù)運(yùn)行。
- X 死亡狀態(tài)(dead): 這個(gè)狀態(tài)只是一個(gè)返回狀態(tài),你不會(huì)在任務(wù)列表里看到這個(gè)狀態(tài)。
- t跟蹤停止?fàn)顟B(tài)(tracing stop)對(duì)應(yīng)內(nèi)核的
TASK_TRACED狀態(tài)。它是 T 停止?fàn)顟B(tài)的特殊變體,專(zhuān)門(mén)用于調(diào)試場(chǎng)景。 - Z僵尸狀態(tài)(zombie)對(duì)應(yīng)內(nèi)核的
EXIT_ZOMBIE狀態(tài)。當(dāng)子進(jìn)程已經(jīng)退出,但父進(jìn)程尚未通過(guò)wait()/waitpid()回收其退出狀態(tài)時(shí),子進(jìn)程就會(huì)進(jìn)入僵尸狀態(tài)。
并且每一個(gè)狀態(tài)都有自己對(duì)應(yīng)的標(biāo)識(shí)符,標(biāo)識(shí)符以數(shù)字的形式表示。比如R狀態(tài)就用 0 代表,S 狀態(tài)就用 1 代表。
3. 查看狀態(tài)
3.1 S 可中斷睡眠狀態(tài)(sleeping)
我們首先創(chuàng)建一個(gè)文件myprocess,然后寫(xiě)入代碼:

編譯運(yùn)行之后,我們來(lái)查看它的狀態(tài):

會(huì)發(fā)現(xiàn)這個(gè)進(jìn)程的狀態(tài)是 S+ ,+ 到底是什么意思我們先不管,我們先看 S ,這代表這個(gè)進(jìn)程目前處于睡眠狀態(tài)。但是我們的程序一直在運(yùn)行啊?一直在執(zhí)行while循環(huán)里面的printf語(yǔ)句,持續(xù)的在屏幕中打印我們所定的內(nèi)容,可為什么這個(gè)進(jìn)程的狀態(tài)還是休眠呢,它不應(yīng)該是運(yùn)行嗎?
我們?cè)賹?myprocess.c 文件中的代碼修改一下:


我們發(fā)現(xiàn)當(dāng)程序持續(xù)執(zhí)行while空語(yǔ)句的時(shí)候,這個(gè)進(jìn)程的狀態(tài)從原來(lái)的睡眠狀態(tài)變成了運(yùn)行狀態(tài)。
這是因?yàn)?,?Linux 操作系統(tǒng)中,進(jìn)程狀態(tài)會(huì)根據(jù)自身執(zhí)行行為發(fā)生明確變化。保留 printf 與注釋 printf 會(huì)讓進(jìn)程呈現(xiàn)完全不同的狀態(tài),其核心原因在于進(jìn)程是否需要等待事件、是否主動(dòng)放棄 CPU。
當(dāng)程序中保留 printf 與 sleep 語(yǔ)句時(shí),進(jìn)程會(huì)在循環(huán)中執(zhí)行輸出操作并主動(dòng)等待。printf 屬于典型的輸出 I/O 操作,即進(jìn)程通過(guò)系統(tǒng)調(diào)用向終端設(shè)備寫(xiě)入數(shù)據(jù),由設(shè)備驅(qū)動(dòng)最終刷新顯示到屏幕;而 sleep 則讓進(jìn)程主動(dòng)等待指定時(shí)長(zhǎng)。
由于 I/O 設(shè)備的處理速度遠(yuǎn)慢于 CPU,進(jìn)程在執(zhí)行 printf 時(shí)無(wú)法立即完成操作,必須等待設(shè)備響應(yīng)。此時(shí)內(nèi)核會(huì)將進(jìn)程從運(yùn)行隊(duì)列移出,掛入對(duì)應(yīng)的等待隊(duì)列,使其主動(dòng)讓出 CPU,進(jìn)入 Linux 下的可中斷睡眠狀態(tài)(S),對(duì)應(yīng)操作系統(tǒng)理論中的阻塞狀態(tài)。直到 I/O 完成或定時(shí)時(shí)間到達(dá),進(jìn)程才會(huì)被喚醒并重新放回運(yùn)行隊(duì)列繼續(xù)執(zhí)行。因此在未注釋 printf 時(shí),進(jìn)程絕大多數(shù)時(shí)間都處于等待狀態(tài),狀態(tài)標(biāo)識(shí)為 S。
當(dāng)程序注釋掉 printf 與 sleep 語(yǔ)句后,進(jìn)程僅執(zhí)行一個(gè)無(wú)限空循環(huán)。該循環(huán)不涉及任何 I/O 操作,不等待任何外部事件,也不會(huì)主動(dòng)放棄 CPU。此時(shí)進(jìn)程始終具備執(zhí)行條件,要么正在 CPU 上運(yùn)行,要么時(shí)間片用完后回到運(yùn)行隊(duì)列等待再次調(diào)度。這兩種情況在 Linux 中統(tǒng)一表示為運(yùn)行 / 就緒狀態(tài)(R)。因此注釋 printf 后,進(jìn)程會(huì)持續(xù)處于 R 狀態(tài),不會(huì)進(jìn)入阻塞。
簡(jiǎn)單來(lái)說(shuō),是否出現(xiàn)等待行為,是決定進(jìn)程狀態(tài)為 R 還是 S 的根本原因:有等待則進(jìn)入阻塞(S),無(wú)等待則保持運(yùn)行 / 就緒(R)。
那既然進(jìn)程處于 S 可中斷睡眠狀態(tài),我們之前講過(guò)可以使用 Ctrl + C 的鍵盤(pán)操作去中斷這個(gè)進(jìn)程,現(xiàn)在,我們還可以使用 kill 命令:

使用 kill -9 PID 就可以強(qiáng)制殺掉這個(gè)正在運(yùn)行或者卡住的進(jìn)程,其中 -9 是 Linux 系統(tǒng)中的信號(hào)編號(hào),代表系統(tǒng)預(yù)定義的 SIGKILL(強(qiáng)制終止信號(hào))。
Linux 操作系統(tǒng)通過(guò)信號(hào)來(lái)控制進(jìn)程的行為,不同的數(shù)字對(duì)應(yīng)不同的指令:

-9 是最強(qiáng)制、最高優(yōu)先級(jí)的終止信號(hào),內(nèi)核會(huì)立即殺死指定進(jìn)程,不允許進(jìn)程忽略、阻塞或處理,進(jìn)程無(wú)法做任何清理操作,直接被系統(tǒng)強(qiáng)制結(jié)束。
普通的 kill PID(不帶 -9)默認(rèn)使用 -15(SIGTERM),屬于溫和的退出信號(hào),允許進(jìn)程保存數(shù)據(jù)、釋放資源后正常關(guān)閉。
接著我們來(lái)講一下S+的 + 的含義:

首先我們寫(xiě)出這樣一段代碼,執(zhí)行一個(gè)死循環(huán),一直睡眠 1 秒,然后去查看進(jìn)程:

大家會(huì)發(fā)現(xiàn),此時(shí)我的進(jìn)程處于 S+ 狀態(tài),當(dāng)我再次輸入各種指令的時(shí)候,我的Shell不做任何反應(yīng),輸入什么內(nèi)容都沒(méi)有用。其實(shí)這是因?yàn)?code>+ 作為狀態(tài)修飾符,表明該進(jìn)程是前臺(tái)進(jìn)程組的成員,Linux 系統(tǒng)默認(rèn)就是讓進(jìn)程在前臺(tái)運(yùn)行,這是系統(tǒng)的標(biāo)準(zhǔn)行為。也就是說(shuō),./myprocess 這一進(jìn)程是一個(gè)前臺(tái)進(jìn)程,前臺(tái)進(jìn)程會(huì)占用當(dāng)前終端,可直接與用戶(hù)交互,且能接收 Ctrl+C、Ctrl+Z 等鍵盤(pán)信號(hào),但是終端會(huì)被其占用,無(wú)法在同一窗口輸入新命令。
如果我不想讓我的進(jìn)程處于前臺(tái)進(jìn)程,那么可以手動(dòng)的加上這一符號(hào):

此時(shí)的狀態(tài)變成了 S :
![]()
所以,在命令末尾添加符號(hào) &,表示將進(jìn)程放到后臺(tái)運(yùn)行。此時(shí)進(jìn)程狀態(tài)從 S+ 變?yōu)?S,+ 符號(hào)消失,意味著進(jìn)程不再占用當(dāng)前終端,用戶(hù)可以繼續(xù)在終端輸入其他指令,且無(wú)法通過(guò) Ctrl + C 直接終止該進(jìn)程。只能通過(guò)kill指令去刪除進(jìn)程。
3.2 D 不可中斷睡眠狀態(tài)(disk sleep)
D狀態(tài)也被稱(chēng)為磁盤(pán)睡眠(Disk Sleep),是 Linux 中一種特殊的阻塞狀態(tài)。
當(dāng)進(jìn)程需要與硬件設(shè)備進(jìn)行關(guān)鍵、不可打斷的數(shù)據(jù)交互時(shí),就會(huì)進(jìn)入 D 狀態(tài)。最典型的場(chǎng)景是進(jìn)程訪問(wèn)磁盤(pán)、讀寫(xiě)文件,此時(shí)進(jìn)程會(huì)向磁盤(pán)設(shè)備發(fā)起 I/O 請(qǐng)求。由于磁盤(pán) I/O 速度遠(yuǎn)慢于 CPU,進(jìn)程必須等待硬件完成操作,不能繼續(xù)執(zhí)行。
為了保證數(shù)據(jù)安全與設(shè)備狀態(tài)穩(wěn)定,內(nèi)核不允許這種等待被信號(hào)打斷。如果進(jìn)程在磁盤(pán)讀寫(xiě)中途被強(qiáng)制終止,可能導(dǎo)致數(shù)據(jù)不完整、文件系統(tǒng)損壞或設(shè)備狀態(tài)異常。因此,內(nèi)核會(huì)將進(jìn)程標(biāo)記為不可中斷睡眠,讓它安靜等待 I/O 結(jié)束,期間不響應(yīng)任何普通信號(hào)。
處于D狀態(tài)的進(jìn)程其實(shí)會(huì)有一定的風(fēng)險(xiǎn)。與常見(jiàn)的 S 狀態(tài)(可中斷睡眠)不同,處于 D 狀態(tài)的進(jìn)程無(wú)法被 Ctrl+C 終止,也無(wú)法被 kill 命令殺死,即使是 kill -9 也無(wú)效。它只能等待 I/O 完成、硬件返回結(jié)果后,由內(nèi)核自動(dòng)喚醒,回到 R 就緒狀態(tài)繼續(xù)執(zhí)行。
所以,大量長(zhǎng)期處于 D 狀態(tài)的進(jìn)程會(huì)占用系統(tǒng)資源與進(jìn)程描述符,導(dǎo)致系統(tǒng)可用進(jìn)程數(shù)量減少,嚴(yán)重時(shí)會(huì)影響新程序啟動(dòng),甚至引發(fā)系統(tǒng)服務(wù)異常。更關(guān)鍵的是,D 狀態(tài)通常意味著 I/O 瓶頸。持續(xù)出現(xiàn) D 狀態(tài)說(shuō)明磁盤(pán)或硬件設(shè)備響應(yīng)緩慢,也就是磁盤(pán)或者硬件設(shè)備老化了。會(huì)導(dǎo)致整個(gè)系統(tǒng) I/O 性能下降,文件讀寫(xiě)卡頓、系統(tǒng)負(fù)載升高,用戶(hù)會(huì)明顯感覺(jué)到操作延遲、程序響應(yīng)變慢。
在極端情況下,如果磁盤(pán)故障或設(shè)備斷開(kāi)導(dǎo)致 I/O 永遠(yuǎn)無(wú)法完成,相關(guān)進(jìn)程會(huì)永久卡在 D 狀態(tài),形成不可殺死的 “僵尸化” 進(jìn)程,只有重啟系統(tǒng)才能徹底清除,嚴(yán)重影響系統(tǒng)穩(wěn)定性與可用性。
不過(guò)一般正常情況下,磁盤(pán) I/O 很快,D 狀態(tài)只會(huì)短暫出現(xiàn),用戶(hù)幾乎感知不到。但如果磁盤(pán)繁忙、I/O 阻塞或設(shè)備異常,進(jìn)程會(huì)長(zhǎng)時(shí)間停留在 D 狀態(tài),表現(xiàn)為系統(tǒng)卡頓、進(jìn)程無(wú)法殺死,這也是判斷 I/O 瓶頸的重要標(biāo)志。
由于D狀態(tài)一般不會(huì)出現(xiàn)或者說(shuō)很難捕捉到D狀態(tài),在這就不做實(shí)際演示。感興趣的可以去大模型搜索一下如何在命令行輸入指令模擬D狀態(tài)進(jìn)程的出現(xiàn),友情提示:這個(gè)實(shí)驗(yàn)可能會(huì)導(dǎo)致你的操作系統(tǒng)崩潰,需要重裝。
3.3T 停止?fàn)顟B(tài)(stopped)
T 狀態(tài)即停止?fàn)顟B(tài),表示進(jìn)程被暫停執(zhí)行,不再參與 CPU 調(diào)度,但進(jìn)程的內(nèi)存、打開(kāi)的文件等資源依然保留,隨時(shí)可以恢復(fù)運(yùn)行。
進(jìn)程進(jìn)入 T 狀態(tài)通常是收到了暫停類(lèi)信號(hào),最常見(jiàn)的是用戶(hù)在終端按下 Ctrl+Z,或是系統(tǒng)調(diào)用 kill -19 PID 發(fā)送 SIGSTOP 信號(hào)。與 S 狀態(tài)、D 狀態(tài)等待 I/O 或事件不同,T 狀態(tài)下的進(jìn)程并非在等待外部條件,而是被強(qiáng)制凍結(jié),內(nèi)核不會(huì)再為其分配時(shí)間片。
比如我們還是使用這段代碼:

運(yùn)行之后,我們對(duì)其使用 kill -19 PID 的指令:

就會(huì)發(fā)現(xiàn)原來(lái)的進(jìn)程從S+的狀態(tài)變?yōu)榱薚狀態(tài)。
處于 T 狀態(tài)的進(jìn)程既不運(yùn)行也不退出,只是暫時(shí) “掛起”。它可以被 kill -18 PID(對(duì)應(yīng) SIGCONT 信號(hào))喚醒,恢復(fù)到之前的 R 或 S 狀態(tài)繼續(xù)執(zhí)行。這種狀態(tài)常用于調(diào)試程序、臨時(shí)暫停任務(wù),是操作系統(tǒng)對(duì)進(jìn)程精細(xì)控制的一種體現(xiàn)。

在前面講解可中斷睡眠狀態(tài)的時(shí)候,我們提到了前臺(tái)進(jìn)程和后臺(tái)進(jìn)程,經(jīng)過(guò)講解我們可以總結(jié)成一句話:前臺(tái)進(jìn)程和后臺(tái)進(jìn)程最大的區(qū)別就是,是否能接收鍵盤(pán)輸入。前臺(tái)進(jìn)程占用終端,能夠獲取用戶(hù)的鍵盤(pán)操作與信號(hào);后臺(tái)進(jìn)程脫離終端控制,無(wú)法接收鍵盤(pán)輸入,用戶(hù)的按鍵操作不會(huì)傳遞給該進(jìn)程。
如果現(xiàn)在有一個(gè)進(jìn)程就是后臺(tái)進(jìn)程,但是這個(gè)進(jìn)程還需要從鍵盤(pán)中獲取輸入,操作系統(tǒng)就會(huì)把它設(shè)置為T(mén)停止?fàn)顟B(tài),就像這種場(chǎng)景:

這段代碼里調(diào)用了scanf函數(shù),所以需要從鍵盤(pán)中獲取輸入。

我們手動(dòng)設(shè)置進(jìn)程后臺(tái)運(yùn)行,此時(shí)該進(jìn)程的狀態(tài)就被設(shè)置成了 T 。
3.4t跟蹤停止?fàn)顟B(tài)(tracing stop)
這個(gè)狀態(tài)對(duì)應(yīng)內(nèi)核的 TASK_TRACED 狀態(tài)。它是 T 停止?fàn)顟B(tài)的特殊變體,專(zhuān)門(mén)用于調(diào)試場(chǎng)景。當(dāng)進(jìn)程被調(diào)試器(如 gdb) attach 或設(shè)置斷點(diǎn)時(shí),會(huì)收到跟蹤信號(hào)并進(jìn)入此狀態(tài)。此時(shí)進(jìn)程處于暫停執(zhí)行,等待調(diào)試器指令(繼續(xù)、單步、斷點(diǎn)恢復(fù)等)。它不僅能被 SIGCONT(kill -18)恢復(fù),還能由調(diào)試器主動(dòng)控制,是系統(tǒng)調(diào)試機(jī)制的核心狀態(tài)之一。

我們剛開(kāi)始調(diào)試這段代碼的時(shí)候,先給代碼打上一個(gè)斷點(diǎn),然后執(zhí)行運(yùn)行指令。在我們執(zhí)行運(yùn)行指令之前這段程序是沒(méi)有被運(yùn)行的,所以我們看到進(jìn)程里面,只有GDP調(diào)試器調(diào)用的一個(gè)myprocess的進(jìn)程。當(dāng)我們運(yùn)行之后由調(diào)試器創(chuàng)建了一個(gè)子進(jìn)程,讓這個(gè)程序得以運(yùn)行。
這個(gè)得以運(yùn)行的程序的狀態(tài)就是 t 跟蹤停止?fàn)顟B(tài)。這就相當(dāng)于父進(jìn)程GDP先創(chuàng)建了一個(gè)子進(jìn)程,遇到斷點(diǎn)的時(shí)候,向子進(jìn)程發(fā)起了kill 19號(hào)信號(hào)。
3.5 X死亡狀態(tài) 和 Z 僵尸狀態(tài)
為了更好的讓大家能理解,我們來(lái)講個(gè)故事:
你叫小明,是一個(gè)朝氣蓬勃的大學(xué)生,非常喜歡跑步。有一天早上六點(diǎn)鐘,你正沿著路上在慢跑,突然從你的后面竄出來(lái)一個(gè)八十歲的老大爺,跑的飛快宛如風(fēng)馳電掣。當(dāng)他跑到你前面一段距離的時(shí)候,突然嘎嘣一下倒在地上站不起來(lái)了。作為一個(gè)有社會(huì)道德的有為青年,你當(dāng)機(jī)立斷打了急救電話和報(bào)警電話,老大爺一個(gè)人直的不能再直的躺在地上等著,過(guò)了一段時(shí)間后警察和急救人員都趕到了。
當(dāng)趕到的時(shí)候,警察和急救人員并不是馬上就把老大爺給抬走,而是先就地檢查老大爺?shù)臓顩r,醫(yī)護(hù)人員判斷老大爺是否已經(jīng)死亡,警察人員判斷老大爺?shù)乃劳鲈虻降资鞘裁础5葯z查和判斷全部完畢之后,醫(yī)護(hù)人員才會(huì)把老大爺拉走,警察人員才會(huì)疏散現(xiàn)場(chǎng)。
在上面這段虛構(gòu)的故事當(dāng)中的老大爺就相當(dāng)于是一個(gè)進(jìn)程,在他躺在地上的時(shí)候,就相當(dāng)于這個(gè)進(jìn)程已經(jīng)結(jié)束。但是老大爺?shù)降子袥](méi)有死亡,還不得而知,需要醫(yī)護(hù)人員來(lái)判斷。對(duì)于進(jìn)程而言,當(dāng)這個(gè)進(jìn)程已經(jīng)結(jié)束,但是還沒(méi)有人來(lái)檢查進(jìn)程的信息的時(shí)候,在這段期間,該進(jìn)程的狀態(tài)就叫做:僵尸狀態(tài)。當(dāng)信息檢查完畢,確認(rèn)該進(jìn)程確實(shí)真的已經(jīng)結(jié)束了,才會(huì)宣判這個(gè)進(jìn)程的狀態(tài)為:死亡狀態(tài)。
不過(guò)要注意的是,死亡狀態(tài)是一個(gè)瞬時(shí)狀態(tài),至少以我們當(dāng)前的知識(shí)儲(chǔ)備,是沒(méi)有直接觀察到進(jìn)程處于死亡狀態(tài)的時(shí)候的。所以大家只要先了解死亡狀態(tài)的概念:死亡狀態(tài)是進(jìn)程徹底退出、所有資源被內(nèi)核完全回收后的最終狀態(tài),進(jìn)程會(huì)從系統(tǒng)中徹底消失,不再留下任何信息。
我們主要要講解的是:僵尸狀態(tài)。
是 Linux 操作系統(tǒng)中進(jìn)程生命周期結(jié)束后的一種特殊中間狀態(tài)。當(dāng)一個(gè)子進(jìn)程執(zhí)行完畢、通過(guò)exit()系統(tǒng)調(diào)用正常退出,或因信號(hào)異常終止時(shí),其用戶(hù)態(tài)內(nèi)存、打開(kāi)的文件描述符、堆棧等運(yùn)行時(shí)資源會(huì)被內(nèi)核立即釋放,但為了向父進(jìn)程提供該進(jìn)程的退出狀態(tài)碼、終止信號(hào)等退出信息,內(nèi)核會(huì)保留該進(jìn)程的進(jìn)程控制塊(PCB/task_struct)與進(jìn)程號(hào)(PID),使其暫時(shí)留在進(jìn)程列表中。此時(shí)進(jìn)程已不再執(zhí)行任何代碼、不占用 CPU 與內(nèi)存資源,卻仍以進(jìn)程形式存在,這種已終止運(yùn)行但退出信息未被父進(jìn)程回收的狀態(tài),即為僵尸狀態(tài),處于該狀態(tài)的進(jìn)程稱(chēng)為僵尸進(jìn)程。
用一句話簡(jiǎn)單理解就是:當(dāng)子進(jìn)程已經(jīng)執(zhí)行完畢退出或被意外終止,而父進(jìn)程仍在運(yùn)行且未及時(shí)回收子進(jìn)程的退出信息時(shí),子進(jìn)程就會(huì)處于僵尸狀態(tài)。
比如說(shuō)對(duì)于這段代碼:


我們創(chuàng)建一個(gè)子進(jìn)程之后,讓父子進(jìn)程單獨(dú)執(zhí)行自己的語(yǔ)句,子進(jìn)程只執(zhí)行一次printf,但父進(jìn)程要持續(xù)執(zhí)行printf。當(dāng)子進(jìn)程的語(yǔ)句已經(jīng)執(zhí)行完畢的時(shí)候,父進(jìn)程依然在執(zhí)行語(yǔ)句。此時(shí)子進(jìn)程雖然已經(jīng)結(jié)束退出了,但退出信息沒(méi)有被父進(jìn)程回收。那么子進(jìn)程的狀態(tài)就會(huì)變成僵尸狀態(tài)。
到這里,對(duì)于僵尸進(jìn)程我們只要有四個(gè)問(wèn)題:
- 進(jìn)程退出了,退出信息是什么?
- 進(jìn)程退出了,退出信息保存在哪里?
- 檢測(cè) Z 狀態(tài)進(jìn)程,回收 Z 狀態(tài)進(jìn)程,本質(zhì)是在做什么?
- 具體怎么回收?誰(shuí)來(lái)回收?
其中第四個(gè)問(wèn)題因?yàn)樯婕暗竭M(jìn)程控制的問(wèn)題,所以我們只是簡(jiǎn)單提一下,后續(xù)文章中會(huì)講解。
首先第一個(gè)和第二個(gè)問(wèn)題:
進(jìn)程的退出信息(Exit Status)是一個(gè)整數(shù)數(shù)值,通常包含兩部分核心內(nèi)容:
1. 退出狀態(tài)碼(Exit Code):進(jìn)程正常結(jié)束時(shí)返回的值(如 main 函數(shù)的返回值,通常 0 表示成功,非 0 表示錯(cuò)誤類(lèi)型)。
2. 終止原因(Termination Reason):進(jìn)程是如何結(jié)束的。包括:
正常退出(Normal Exit):如 return 0、exit(1)。
異常退出(Abnormal Exit):如被信號(hào)殺死(Segmentation Fault 段錯(cuò)誤、SIGKILL 強(qiáng)制終止等),此時(shí)會(huì)記錄導(dǎo)致退出的信號(hào)編號(hào)
退出信息是被存儲(chǔ)在 當(dāng)前子進(jìn)程自己的task_struct 結(jié)構(gòu)體里,也就是說(shuō)子進(jìn)程雖然結(jié)束了,但是它的 task_struct 是一直保留的,這也是我們能在狀態(tài)查看是看到這個(gè)子進(jìn)程的PID的原因。之所以存儲(chǔ) task_struct,這是為了:父進(jìn)程未來(lái)通過(guò) wait() 或 waitpid() 系統(tǒng)調(diào)用時(shí),內(nèi)核會(huì)從這里讀取數(shù)據(jù)并復(fù)制給父進(jìn)程。

exit_state就代表退出時(shí)的狀態(tài),exit_code 就是退出編碼。
第三個(gè)問(wèn)題:
本質(zhì)是在 “讀取數(shù)據(jù)” 與 “釋放占位”。
讀取數(shù)據(jù)(讀操作):父進(jìn)程通過(guò)調(diào)用 wait()/waitpid(),主動(dòng)去讀取子進(jìn)程 task_struct 中遺留的退出信息(退出碼 / 信號(hào))。這是父子進(jìn)程間最后的通信儀式,父進(jìn)程必須確認(rèn)子進(jìn)程是 “成功了” 還是 “出錯(cuò)了”。
釋放資源(清理操作):當(dāng)讀取完成后,內(nèi)核確認(rèn)不再需要該進(jìn)程的任何信息,才會(huì)徹底釋放子進(jìn)程占用的 PID(進(jìn)程號(hào)) 和 task_struct 結(jié)構(gòu)。
第四個(gè)問(wèn)題:
誰(shuí)來(lái)回收?
主動(dòng)回收:由父進(jìn)程主動(dòng)調(diào)用 wait() 或 waitpid() 函數(shù)。
被動(dòng) / 繼承回收:如果父進(jìn)程先于子進(jìn)程退出,子進(jìn)程會(huì)被托管給 init 進(jìn)程(PID 1) 或系統(tǒng)守護(hù)進(jìn)程,由它們自動(dòng)循環(huán)調(diào)用 wait() 來(lái)回收所有孤兒進(jìn)程的僵尸狀態(tài)。
具體怎么回收?
阻塞等待:父進(jìn)程調(diào)用 wait(),如果子進(jìn)程還在運(yùn)行,父進(jìn)程會(huì)進(jìn)入阻塞狀態(tài)(S),直到子進(jìn)程退出。
獲取狀態(tài):子進(jìn)程退出后,內(nèi)核將退出信息填入 wait() 的參數(shù)中,父進(jìn)程讀取。
徹底銷(xiāo)毀:內(nèi)核檢測(cè)到所有進(jìn)程引用都已解除,釋放僵尸進(jìn)程的資源,使其變?yōu)?X 狀態(tài)并消失。
以上問(wèn)題回答中的 wait () ,實(shí)際上是一個(gè)系統(tǒng)調(diào)用,叫做等待函數(shù),后續(xù)我們會(huì)提到,大家暫時(shí)只要知道有這么個(gè)東西就行。
最后還有一個(gè)問(wèn)題需要大家理解:如果說(shuō)父進(jìn)程一直不回收子進(jìn)程會(huì)怎么樣?
首先一定會(huì)出現(xiàn)的情況就是:子進(jìn)程的PID也沒(méi)有被回收,如果說(shuō)創(chuàng)建的進(jìn)程太多,PID不夠用了,就會(huì)導(dǎo)致進(jìn)程創(chuàng)建出現(xiàn)問(wèn)題;另外:子進(jìn)程的task_struct一直沒(méi)有被釋放,會(huì)占用內(nèi)存空間資源,這就是內(nèi)存泄漏的問(wèn)題。
那么就有一個(gè)衍生的問(wèn)題:如果一個(gè)對(duì)應(yīng)的進(jìn)程已經(jīng)結(jié)束了,內(nèi)存泄露的問(wèn)題還會(huì)存在嗎?為了讓大家能更好的理解,我說(shuō)一個(gè)場(chǎng)景:當(dāng)你打開(kāi)一個(gè)游戲正在愉快的玩耍的時(shí)候,同時(shí)你的后臺(tái)又在掛著網(wǎng)易云音樂(lè)聽(tīng)歌,同時(shí)你的后臺(tái)還在下載電影,對(duì)于部分手機(jī)或者電腦來(lái)說(shuō),你就會(huì)發(fā)現(xiàn)你在玩游戲的過(guò)程當(dāng)中非常的卡頓,這就是內(nèi)存空間不足導(dǎo)致的問(wèn)題。當(dāng)你把后臺(tái)下載電影的軟件關(guān)掉,音樂(lè)軟件也關(guān)掉,就會(huì)發(fā)現(xiàn)打游戲會(huì)變得無(wú)比絲滑順暢。這就相當(dāng)于釋放內(nèi)存,清理內(nèi)存空間的操作。
所以我們可以得到結(jié)論:如果一個(gè)進(jìn)程已經(jīng)結(jié)束了,那么該進(jìn)程導(dǎo)致的內(nèi)存泄漏問(wèn)題就會(huì)消失。
所以對(duì)于我們平時(shí)使用的絕大部分軟件,除非當(dāng)我們點(diǎn)擊退出,否則這個(gè)軟件程序就會(huì)一直運(yùn)行,其本質(zhì)上就是這個(gè)軟件在進(jìn)行死循環(huán),屬于內(nèi)存泄漏問(wèn)題。像這種一直運(yùn)行的進(jìn)程,就叫做常駐進(jìn)程。
3.6 孤兒進(jìn)程
我們前面提到了,如果子進(jìn)程運(yùn)行已經(jīng)結(jié)束或被信號(hào)等其他指令殺死,且父進(jìn)程還沒(méi)有回收子進(jìn)程的退出信息,那么子進(jìn)程的狀態(tài)就會(huì)被判定為僵尸狀態(tài)。就相當(dāng)于,父進(jìn)程還在運(yùn)行,但子進(jìn)程先退出了。那如果是父進(jìn)程先退出了,子進(jìn)程還在運(yùn)行,那么會(huì)是什么情況呢?
這就涉及到一個(gè)進(jìn)程概念:孤兒進(jìn)程。
孤兒進(jìn)程是指在程序運(yùn)行過(guò)程中,父進(jìn)程先于子進(jìn)程退出,而子進(jìn)程仍然繼續(xù)執(zhí)行所形成的特殊進(jìn)程。當(dāng)父進(jìn)程正常結(jié)束或異常終止后,原本由其管理的子進(jìn)程失去了原有的父進(jìn)程,便成為孤兒進(jìn)程。
我們以這段代碼為例:

我們使用這一行指令來(lái)控制持續(xù)查看進(jìn)程:
![]()

大家會(huì)發(fā)現(xiàn),當(dāng)子進(jìn)程一直在進(jìn)行的時(shí)候父進(jìn)程已經(jīng)結(jié)束了,于是在下一次執(zhí)行程序的時(shí)候,子進(jìn)程的PPID就由原來(lái)的5568變成了 1 ,而 1 就代表操作系統(tǒng)的初始進(jìn)程,即操作系統(tǒng)內(nèi)核 PID=1的進(jìn)程。所以此時(shí)該子進(jìn)程就變成了一個(gè)孤兒進(jìn)程,并且交給了 PID = 1 的進(jìn)程,即操作系統(tǒng)內(nèi)核托管。
之所以會(huì)被回收托管,是 為了保證系統(tǒng)資源能夠正常回收,Linux 內(nèi)核會(huì)自動(dòng)將這類(lèi)孤兒進(jìn)程 “過(guò)繼” 給系統(tǒng)中的 init 進(jìn)程(PID 為 1)或 systemd 進(jìn)程托管,由其負(fù)責(zé)后續(xù)的資源回收工作,因此孤兒進(jìn)程在退出時(shí)會(huì)被及時(shí)清理,不會(huì)像僵尸進(jìn)程那樣長(zhǎng)期占用系統(tǒng)資源。
同時(shí),我們發(fā)現(xiàn)子進(jìn)程的進(jìn)程狀態(tài)由原來(lái)的 S+ 變成了 S ,也就是從前臺(tái)進(jìn)程變成了后臺(tái)進(jìn)程,所以當(dāng)我們想使用 Ctrl+C 的操作去關(guān)閉進(jìn)程的時(shí)候,是關(guān)閉不了的,只有通過(guò)kill指令才能關(guān)閉。這是因?yàn)椋篠+ 中的 + 代表進(jìn)程屬于前臺(tái)終端進(jìn)程組,與控制終端關(guān)聯(lián)。當(dāng)父進(jìn)程(終端 Shell)退出后,孤兒進(jìn)程被內(nèi)核重新托管給 init 進(jìn)程,并脫離原終端,不再屬于前臺(tái)進(jìn)程組,因此 + 符號(hào)消失,狀態(tài)變?yōu)?S。進(jìn)程本身仍處于可中斷睡眠狀態(tài),并未發(fā)生本質(zhì)改變。
4. 進(jìn)程優(yōu)先級(jí)基本概念
進(jìn)程優(yōu)先級(jí)是操作系統(tǒng)用于決定多個(gè)進(jìn)程誰(shuí)先獲得 CPU 資源、誰(shuí)后執(zhí)行的調(diào)度依據(jù),它決定了進(jìn)程在競(jìng)爭(zhēng)處理器時(shí)的 “重要程度” 和 “排隊(duì)順序”。優(yōu)先級(jí)越高的進(jìn)程,在系統(tǒng)資源緊張時(shí)越容易被調(diào)度器優(yōu)先選中運(yùn)行;優(yōu)先級(jí)越低,則越容易被高優(yōu)先級(jí)進(jìn)程 “搶占”,等待時(shí)間更長(zhǎng)。
5.查看系統(tǒng)進(jìn)程
我們前面學(xué)習(xí)過(guò) ps axj 指令,可以查看到進(jìn)程的PID和其他的詳細(xì)信息,現(xiàn)在我們來(lái)學(xué)習(xí)ps -l 指令:

我們先執(zhí)行了一個(gè)程序 peocessTest,然后查看它的進(jìn)程信息。首先我們來(lái)看UID,這代表啟動(dòng)這個(gè)程序的用戶(hù)的名稱(chēng),因?yàn)閷?duì)于操作系統(tǒng)來(lái)說(shuō),它會(huì)把我們的用戶(hù)名轉(zhuǎn)化成一個(gè)編號(hào)以用來(lái)區(qū)分是誰(shuí)運(yùn)行了哪些程序。比如我的用戶(hù)名 chen ,在操作系統(tǒng)中的編號(hào)就是 1001 :

其次,進(jìn)程信息中的 PRI 和 NI 就代表優(yōu)先級(jí)信息。
6. PRI 和 NI
PRI 是進(jìn)程的實(shí)際優(yōu)先級(jí)(Priority),由操作系統(tǒng)內(nèi)核動(dòng)態(tài)計(jì)算和調(diào)度,數(shù)值越小表示進(jìn)程優(yōu)先級(jí)越高,越容易被 CPU 優(yōu)先執(zhí)行。
NI 即 nice 值,是用戶(hù)可以手動(dòng)設(shè)置的優(yōu)先級(jí)修正值,用于影響最終的 PRI。之所以叫 nice ,是因?yàn)槿Q(chēng)是 nice value,其中的nice的中文意思是:(調(diào)度器)偏好 / 友好程度。
nice 越低(越嚴(yán)格):進(jìn)程的優(yōu)先級(jí)越高,系統(tǒng)會(huì)優(yōu)先照顧它(比如實(shí)時(shí)任務(wù)、關(guān)鍵服務(wù))。
nice 越高(越客氣):進(jìn)程的優(yōu)先級(jí)越低,系統(tǒng)會(huì)盡量少占用它的資源(比如后臺(tái)任務(wù)、非關(guān)鍵進(jìn)程)。
在 Linux 中,nice 值范圍通常為 -20 ~ 19,NI 越小,優(yōu)先級(jí)越高;NI 越大,優(yōu)先級(jí)越低。普通進(jìn)程的 PRI 一般會(huì)在默認(rèn)基礎(chǔ)上加上 nice 值得到最終優(yōu)先級(jí),用戶(hù)通過(guò)調(diào)整 NI 可以間接控制進(jìn)程優(yōu)先級(jí),普通用戶(hù)只能調(diào)高 NI(降低優(yōu)先級(jí)),只有 root 權(quán)限才能降低 NI(提升優(yōu)先級(jí))。
系統(tǒng)調(diào)度器依據(jù) PRI 分配 CPU 時(shí)間片,從而保證重要進(jìn)程更及時(shí)地運(yùn)行。
手動(dòng)修改 NI 值的方法就是調(diào)用 top 命令:

當(dāng)我們輸入top指令的時(shí)候,會(huì)彈出來(lái)當(dāng)前操作系統(tǒng)內(nèi)所有正在運(yùn)行的進(jìn)程。然后我們?cè)侔匆幌翿鍵,系統(tǒng)會(huì)提醒我們要把哪個(gè)進(jìn)程的 NI 值進(jìn)行修改,接著輸入進(jìn)程的 PID ,然后再輸入你想把該進(jìn)程的優(yōu)先級(jí)改成多少:

比如我們把 NI 改成 10 ,那PRI就會(huì)變成 90 。
所以這里優(yōu)先級(jí)的改變有一個(gè)公式:PRI(new) = PRI(old) + NI ;其中這里的 PRI(old)指的是進(jìn)程的初始的PRI。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
apache啟動(dòng)報(bào)錯(cuò):the requested operation has failed解決辦法
apache啟動(dòng)報(bào)錯(cuò):the requested operation has failed解決辦法2009-11-11
禁止網(wǎng)站顯示文件目錄列表的2個(gè)方法(htaccess)
這篇文章主要介紹了禁止網(wǎng)站顯示文件目錄列表的2個(gè)方法,需要的朋友可以參考下2016-04-04
解決centos桌面在虛擬機(jī)中界面顯示太小問(wèn)題
這篇文章主要介紹了解決centos桌面在虛擬機(jī)中界面顯示太小問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
查看linux文件系統(tǒng)塊大小的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇查看linux文件系統(tǒng)塊大小的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11

