【Linux】Linux進程狀態和僵尸進程:一篇看懂“進程在忙啥”

前言:歡迎各位光臨本博客,這里小編帶你直接手撕Make/Makefile (自動化構建),文章并不復雜,愿諸君耐其心性,忘卻雜塵,道有所長!!!!

解釋_chmod_命令_(3).gif

**🔥個人主頁:IF’Maxue-CSDN博客

🎬作者簡介:C++研發方向學習者

📖**個人專欄:
《C語言》
《C++深度學習》
《Linux》
《數據結構》
《數學建模》
**

??人生格言:生活是默默的堅持,毅力是永久的享受。不破不立,遠方請直行!

文章目錄

    • 一、先搞懂:進程狀態藏在哪?
    • 二、課本里的核心邏輯:3句話說透
    • 三、基礎三態:運行、阻塞、掛起(大白話版)
      • 1. 運行態:“在工位上,要么干活要么等活”
      • 2. 阻塞態:“等材料,暫時離開工位”
      • 3. 掛起態:“工位不夠,去臨時倉庫待著”
    • 四、內核小知識:用“鏈表”管進程
    • 五、Linux實際進程狀態:逐個拆,附代碼
      • 1. R狀態:運行態(Running)
      • 2. S狀態:可中斷休眠(淺睡眠)
      • 3. T狀態:暫停態(Stopped)
      • 4. t狀態:斷點態(Trace Stopped)
      • 5. D狀態:不可中斷休眠(深睡眠)
      • 6. Z狀態:僵尸態(Zombie)
      • 7. X狀態:死亡態(Dead)
    • 六、孤兒進程:爹跑了,誰管孩子?
      • 為啥要領養?
    • 七、總結:3個核心記牢

一、先搞懂:進程狀態藏在哪?

進程不是“黑盒子”,它的所有信息——比如在干啥、代碼存在哪、有啥權限——都記在一個叫task_struct的“檔案本”里。而進程狀態,就是這個檔案本里的一個整數,像員工的“工作狀態標簽”,直接告訴操作系統“這進程現在能干活不”。

image.png

二、課本里的核心邏輯:3句話說透

不管啥操作系統,進程狀態的底層邏輯都逃不開這3點(對應你放的課本截圖):
image.png

  1. 進程不只有“跑”和“不跑”,有好幾種狀態;
  2. 狀態能互相轉——比如“等鍵盤輸入”時會從“能跑”變“等著”,輸入完又變回去;
  3. 只有“運行狀態”的進程,才真正拿著CPU干活。

三、基礎三態:運行、阻塞、掛起(大白話版)

咱們用“工廠干活”的例子理解,比硬記定義簡單:

1. 運行態:“在工位上,要么干活要么等活”

操作系統里,每個CPU都有一個“調度隊列”(像工廠的“待崗工位”),里面放的全是task_struct(進程檔案本)。
只要進程在這個隊列里,狀態就是運行態(Running) ——不管是正在被CPU“叫去干活”,還是排隊等CPU,都算運行態。

調度時,CPU會按規則(比如“先進先出”FIFO)從隊列里挑一個檔案本,找到對應的代碼和數據,讓它跑起來。
image.png

2. 阻塞態:“等材料,暫時離開工位”

比如你寫了個帶scanf的程序——運行后不敲鍵盤,進程就“卡住了”。這不是它偷懶,是它在等“鍵盤輸入”這個“材料”,這就是阻塞。

操作系統怎么管這種情況?它會給每個硬件(鍵盤、磁盤、網卡)建個“設備檔案”(struct device),檔案里專門留了個“等待隊列”——所有等這個硬件的進程,都會被移到這個隊列里。
簡單說:阻塞 = 進程檔案本從“調度隊列”挪到“硬件等待隊列”,直到“材料”備好(比如你敲了鍵盤),再挪回調度隊列。
image.png
image.png
image.png

3. 掛起態:“工位不夠,去臨時倉庫待著”

如果內存實在不夠(工廠工位滿了),操作系統會把進程的“代碼和數據”挪到磁盤(臨時倉庫),只留task_struct(檔案本)在內存——這叫“阻塞掛起”(本來就在等材料,現在連工具都收起來了)。
要是內存還不夠,連調度隊列里的進程也會被挪去磁盤,叫“運行掛起”(本來在等活,現在先去倉庫)。

不過不用記這么細——Linux里不細分掛起態,咱們重點看實際能用的狀態就行。
image.png
image.png
image.png

四、內核小知識:用“鏈表”管進程

操作系統不是瞎管進程的,靠的是“鏈表”這種數據結構。Linux用的是list_head鏈表,特點很實用:

  • 每個task_struct里可以放多個list_head(像一個員工有多個“身份標簽”);
  • 這樣一個進程能同時屬于多個鏈表——比如既在“進程組鏈表”,又在“調度隊列鏈表”;
  • 想通過list_head找到完整的task_struct?靠“地址偏移”——知道list_head在檔案本里的位置,就能算出整個檔案本的地址。

簡單說:進程狀態切換,本質就是list_head在不同鏈表間“挪位置”,無非是增刪查改的操作。
image.png
image.png
image.png
image.png
image.png
image.png

五、Linux實際進程狀態:逐個拆,附代碼

Linux的進程狀態存在task_state_array里,咱們逐個講,每個都給代碼例子,跟著做就能看懂。

1. R狀態:運行態(Running)

  • 特點:在調度隊列里,要么正在跑,要么等CPU;不能被kill打斷(想停它得等它自己出隊列)。
  • 為啥有時查不到?比如printf這種操作太快,進程瞬間切到其他狀態,得用“死循環不做IO”才能穩定抓到。

代碼例子(抓R狀態):

#include <stdio.h>
int main() {while(1); // 死循環,不做任何IO,一直待在調度隊列return 0;
}
  • 操作步驟:
    1. 編譯:gcc test.c -o test
    2. 后臺運行(不占終端):./test &
    3. 查看狀態:ps aux | grep test,會看到狀態是R

image.png
image.png
image.png
image.png
(注:狀態后的+表示“前臺進程”,后臺進程沒有+

2. S狀態:可中斷休眠(淺睡眠)

  • 特點:等資源(鍵盤、文件),處于“淺睡”;能被kill命令打斷(比如等輸入時,kill一下就退出)。
  • 最常見的阻塞態,比如scanf等輸入、讀文件時都算S狀態。

代碼例子(抓S狀態):

#include <stdio.h>
int main() {int a;scanf("%d", &a); // 等鍵盤輸入,進程阻塞,狀態變Sprintf("%d\n", a);return 0;
}
  • 操作步驟:
    1. 運行:./test,不輸入任何內容;
    2. 另開終端查狀態:ps aux | grep test,狀態是S
    3. 測試kill:kill 進程號,進程會直接退出(S狀態能被打斷)。

image.png
image.png

3. T狀態:暫停態(Stopped)

  • 特點:進程被“暫停”,既不在調度隊列也不在等待隊列;得用命令恢復kill -18)。
  • 觸發方式:按ctrl+z暫停前臺進程,或用kill -19手動暫停。

操作例子

  1. 運行上面的scanf程序:./test
  2. ctrl+z,終端提示“已暫停”;
  3. 查狀態:ps aux | grep test,狀態是T
  4. 恢復:kill -18 進程號,進程繼續等輸入;
  5. 再暫停:kill -19 進程號,變回T。

image.png

4. t狀態:斷點態(Trace Stopped)

  • 特點:只有調試時會出現!進程在斷點處停下,比如gdb設斷點后運行。

操作例子

  1. 用gdb調試:gdb ./test
  2. 設斷點:b main(在main函數開頭停);
  3. 運行:r
  4. 另開終端查狀態:ps aux | grep test,狀態是t

image.png
image.png

5. D狀態:不可中斷休眠(深睡眠)

  • 特點:等“關鍵資源”(比如磁盤IO),處于“深睡”;kill -9都殺不掉(怕打斷磁盤操作導致數據損壞)。
  • 常見場景:用dd命令拷貝大文件時。

操作例子(抓D狀態):

  1. 執行磁盤讀寫命令:dd if=/dev/zero of=/tmp/test bs=1G count=10(往/tmp寫10G文件);
  2. 另開終端查狀態:ps aux | grep dd,狀態是D
  3. 試殺:kill -9 進程號,進程紋絲不動,直到磁盤操作完成才退出。

image.png
image.png

6. Z狀態:僵尸態(Zombie)

  • 特點:子進程退出了,但父進程沒“要它的退出信息”(比如退出碼),只剩task_struct(檔案本)在內存;不能被調度,也殺不掉(因為進程已經死了,只剩空殼)。
  • 風險:僵尸進程占內存,父進程一直不管就會“內存泄露”(尤其是開機就跑的常駐進程)。

代碼例子(造僵尸進程):

#include <stdio.h>
#include <unistd.h>
int main() {pid_t pid = fork(); // 創建子進程if (pid == 0) {// 子進程:直接退出,沒被回收printf("子進程PID:%d\n", getpid());return 0;} else if (pid > 0) {// 父進程:死循環,不回收子進程while(1) sleep(1); }return 0;
}
  • 操作步驟:
    1. 運行:./test
    2. 查狀態:ps aux | grep test,會看到子進程狀態是Z
    3. 解決辦法:讓父進程調用wait()回收,或殺掉父進程(子進程會被領養)。

image.png
(注:slab是Linux內核的內存分配機制,專門管理像task_struct這樣的小對象,僵尸進程的task_struct就存在這里,不回收會占 slab 內存)
image.png

7. X狀態:死亡態(Dead)

  • 特點:進程徹底退出,所有資源(代碼、數據、task_struct)被OS回收;看不到這個狀態(因為瞬間就沒了),只是理論上的狀態。

六、孤兒進程:爹跑了,誰管孩子?

如果父進程先退出,子進程沒人管,就成了“孤兒進程”——這時候Linux會讓1號進程領養它:

  • 新內核(比如Ubuntu、CentOS 7+):1號進程是systemd
  • 老內核:1號進程是init

為啥要領養?

怕孤兒進程退出后沒人回收,變成僵尸進程,導致內存泄露。1號進程會負責“要它的退出信息”,相當于“福利院”。

代碼例子(造孤兒進程):

#include <stdio.h>
#include <unistd.h>
int main() {pid_t pid = fork();if (pid == 0) {// 子進程:睡10秒,等父進程先退出printf("子進程PID:%d,當前父進程PID:%d\n", getpid(), getppid());sleep(10); printf("子進程現在父進程PID:%d\n", getppid()); // 會變成1return 0;} else if (pid > 0) {// 父進程:馬上退出,不管子進程printf("父進程退出,PID:%d\n", getpid());return 0;}return 0;
}
  • 操作步驟:
    1. 運行:./test
    2. 父進程瞬間退出,子進程一開始的父進程是終端(比如bash);
    3. 10秒后,子進程的父進程變成1(被1號進程領養);
    4. 孤兒進程會變成后臺進程,終端看不到它的輸出(除非重定向)。

image.png
image.png
image.png
image.png
image.png
image.png

七、總結:3個核心記牢

  1. 進程狀態本質:task_struct在不同鏈表間挪位置(調度隊列、等待隊列);
  2. Linux重點狀態:R(跑)、S(淺睡等資源)、D(深睡殺不掉)、Z(僵尸要回收)、T(暫停);
  3. 孤兒/僵尸處理:孤兒找1號進程領養,僵尸靠父進程wait()回收,避免內存泄露。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95583.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95583.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95583.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開源視頻剪輯工具推薦

開源視頻剪輯和處理工具近年來發展非常迅速&#xff0c;許多工具的功能已經足以媲美甚至超越一些商業軟件。以下是一些頂級的開源視頻編輯和處理工具&#xff0c;涵蓋了從簡單易用到專業級別的不同需求。 一、 主要視頻編輯軟件&#xff08;非線性編輯&#xff0c;NLE&#xf…

第十四屆藍橋杯青少組C++國賽[2023.5.28]第二部分編程題(4、 數獨填數)

參考程序&#xff1a;#include <bits/stdc.h> using namespace std;char board[9][9];// 檢查在 (r,c) 填 num 是否有效 bool isValid(int r, int c, char num) {for (int i 0; i < 9; i) {if (board[r][i] num) return false; // 同行if (board[i][c] num) r…

C語言中奇技淫巧08-使用alloca/__builtin_alloca從棧上分配空間

alloca是什么? alloca 是一個非標準但廣泛支持的 C 語言函數&#xff0c;用于在當前函數的棧&#xff08;stack&#xff09;上動態分配內存。 與 malloc 的區別&#xff1a; malloc 在堆&#xff08;heap&#xff09; 上分配內存&#xff0c;需要手動調用 free 釋放。alloca 在…

【Markdown轉Word完整教程】從原理到實現

Markdown轉Word完整教程&#xff1a;從原理到實現 前言 在技術文檔編寫和學術論文創作中&#xff0c;Markdown因其簡潔的語法和良好的可讀性而廣受歡迎。然而&#xff0c;在實際工作中&#xff0c;我們經常需要將Markdown文檔轉換為Word格式&#xff0c;以便與同事協作、提交正…

IBM穿孔卡片:現代計算技術的奠基之作

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 1 打孔卡概述 穿孔卡片&#xff08;Punch Card&#xff09;又稱打孔卡…

亞馬遜旺季來臨如何用woot沖刺

在亞馬遜旺季來臨之際&#xff0c;使用Woot沖刺需結合新品推廣、老品激活、庫存清理等不同場景&#xff0c;通過精準選品、活動設置、廣告配合及數據監控實現銷量與排名的雙重提升。以下是具體操作指南&#xff1a;一、精準選品&#xff1a;匹配提報條件新品期選品標準&#xf…

AlexNet:計算機視覺的革命性之作

AlexNet: Revolutionizing Deep Learning for Computer Vision (1)網絡提出的背景 論文題目:ImageNet Classification with Deep Convolutional Neural Networks arXiv地址:https://arxiv.org/abs/1207.0575 在2012年ImageNet大規模視覺識別挑戰賽(ILSVRC)中,AlexNet以15…

【高等數學】第十一章 曲線積分與曲面積分——第二節 對坐標的曲線積分

上一節&#xff1a;【高等數學】第十一章 曲線積分與曲面積分——第一節 對弧長的曲線積分 總目錄&#xff1a;【高等數學】 目錄 文章目錄1. 對坐標的曲線積分的概念與性質1. 對坐標的曲線積分的概念與性質 變力沿曲線所作的功 先用曲線 LLL 上的點 M1(x1,y1),M2(x2,y2),…,M…

解析SQL Server核心服務與功能

SQL Server 安裝后會在 Windows 系統中注冊多個服務&#xff0c;每種服務負責不同的功能。主要服務類型包括&#xff1a; &#x1f4cc; 核心服務 (必須或常用)SQL Server Database Engine (數據庫引擎服務) 服務名稱格式&#xff1a; MSSQL$<InstanceName> (命名實例) 或…

專項智能練習(計算機動畫基礎)

1.小明在制作Flash作品時&#xff0c;舞臺及庫中素材如第下圖所示&#xff0c;把“馬”元件插入到“馬”圖層第1幀并放在舞臺的草地位置&#xff0c;發現舞臺中并無馬圖像顯示&#xff0c;下列情形中最有可能的是&#xff08; &#xff09;。A.“馬”圖層已被鎖定 B.“馬”圖層…

第三方庫集成:結合 Express.js 構建本地服務器

引言&#xff1a;Express.js 在 Electron 第三方庫集成中的本地服務器構建價值 在 Electron 框架的第三方庫集成生態中&#xff0c;Express.js 作為 Node.js 的經典 Web 框架&#xff0c;扮演著構建本地服務器的關鍵角色。它不僅僅是一個路由和中間件工具&#xff0c;更是 Elec…

百度地圖+vue+flask+爬蟲 推薦算法旅游大數據可視化系統Echarts mysql數據庫 帶沙箱支付+圖像識別技術

F012 百度地圖vueflask爬蟲 推薦算法旅游大數據可視化系統Echarts mysql數據庫 帶沙箱支付圖像識別技術 &#x1f4da;編號&#xff1a; F012 文章結尾部分有CSDN官方提供的學長 聯系方式名片 博主開發經驗15年,全棧工程師&#xff0c;專業搞定大模型、知識圖譜、算法和可視化…

# 開發中使用——鴻蒙CoreSpeechKit讓文字發聲后續

開發中使用——鴻蒙CoreSpeechKit讓文字發聲后續 設置音量大小 volume// 設置播報相關參數this.extraParam {"queueMode": 0, "speed": AppModel.speed, "volume": AppModel.volume, "pitch": 1, "languageContext": zh-CN,…

Java全棧開發面試實錄:從基礎到微服務的深度探索

Java全棧開發面試實錄&#xff1a;從基礎到微服務的深度探索 面試官與應聘者的初次見面 面試官&#xff1a;你好&#xff0c;很高興見到你。請先做個自我介紹吧。 應聘者&#xff1a;您好&#xff0c;我叫李明&#xff0c;今年28歲&#xff0c;是南京大學計算機科學與技術專業的…

前端路由切換不再白屏:React/Vue 實戰優化全攻略(含可運行 Demo)

摘要 在單頁應用&#xff08;SPA&#xff09;開發中&#xff0c;React、Vue、Angular 這些主流框架都依賴前端路由來完成頁面切換。好處是顯而易見的&#xff1a;首屏資源一次加載&#xff0c;后續頁面切換靠前端路由完成&#xff0c;體驗比傳統的多頁應用要順暢很多。 但是在實…

C#之LINQ

文章目錄前言LINQ一、LINQ1一、LINQ2一、LINQ3Where方法&#xff1a;每一項數據都會進過predicate的測試&#xff0c;如果針對一個元素&#xff0c;predicate執行的返回值為true&#xff0c;那么這個元素就會放到返回值中。獲取一條數據&#xff08;是否帶參數的兩種寫法&#…

第 2 講:Kafka Topic 與 Partition 基礎

課程概述 在第一篇課程中&#xff0c;我們了解了 Kafka 的基本概念和簡單的 Producer/Consumer 實現。 本篇課程將深入探討 Kafka 的核心機制&#xff1a;Topic 和 Partition。 學習目標 通過本課程&#xff0c;您將掌握&#xff1a; Topic 和 Partition 的設計原理&#x…

三階Bezier曲線曲率極值及對應的u的計算方法

三階&#xff08;三次&#xff09;Bezier曲線的曲率極值及其對應的參數 u 的計算是一個復雜的非線性優化問題。由于三階Bezier曲線是參數化曲線&#xff0c;其曲率表達式較為復雜&#xff0c;通常無法通過解析方法直接求得所有極值點&#xff0c;但可以通過求解曲率導數為零的方…

Unity:XML筆記(二)——Xml序列化、反序列化、IXmlSerializable接口

寫在前面&#xff1a;寫本系列(自用)的目的是回顧已經學過的知識、記錄新學習的知識或是記錄心得理解&#xff0c;方便自己以后快速復習&#xff0c;減少遺忘。三、Xml序列化序列化就是把想要存儲的內容轉換為字節序列用于存儲或傳遞。1、序列化我們先創建一個類&#xff0c;之…

java注解、Lambda表達式、Servlet

一、Java注解注解的概念&#xff1a; Java注解是代碼中的元數據&#xff0c;可以用于描述其他代碼。注解在編譯、類加載、運行時被處理&#xff0c;并且不會改變代碼邏輯。注解的用途&#xff1a; 提供代碼元信息&#xff0c;如 Override 表明一個方法覆蓋了父類的方法。 編譯檢…