天天看點

值得收藏-史上最全Linux ps指令詳解

一、程式員的疑惑

  大概在十多年前,我當時還是一個産品經理。由于一些工作的原因,需要向運維工程師學習一些linux常用指令。當使用linux ps這個十分常用的指令時,遇到了一個小小的疑惑。有些工程師推薦使用ps aux的指令組合,有些工程師推薦使用ps -aux的指令組合,從輸出結果上來看似乎也沒有什麼不同。考慮到如常用的ls -l指令在内,很多linux指令選項前都要加上一個短橫線,這麼來看似乎ps -axu是正确的。但是一些早期的linux版本,在執行ps -axu時又會報出如下錯誤Warning: bad syntax,而ps aux卻沒有這樣的報錯資訊,這麼看來似乎ps aux又是正确的。查閱市面上的一些linux書籍,在介紹linux ps指令示例時,有些說用ps aux,而有些又說用ps -axu。實在是讓我這個初學者摸不着頭腦。

值得收藏-史上最全Linux ps指令詳解

再後來,随着我加入運維團隊對linux ps指令逐漸深入使用,學會了檢視man page和help,發現其中有ps指令的exmaple,果然是ps aux的用法是正确的。不過随着對linux ps指令使用的逐漸深入,對ps指令的其他疑問越來越多。比如,我們天天在使用ps指令時輸出的%CPU列到底是什麼含義?為什麼和top顯示的%CPU的值有時候差異非常大?再比如,當我使用ps -el指令時,為什麼我的程序名是systemd-journald,而ps指令隻顯示systemd-journal,弄丢了最後1個字母d。

帶着這麼多疑惑,3年多前我有機會簡單的學習了一下linux ps源代碼,逐漸解開了上面這些疑惑。後來發現公司的很多同僚也對ps指令有各種問題和疑問,于是想把之前對ps指令的學習經驗總結成文檔,供大家參考。希望能給大家帶來幫助。

二、Linux ps指令選項解析

Linux ps指令功能很強大,了解ps指令首先需要從ps指令的選項格式入手。像其他很多linux shell指令一樣,ps指令的選項也有長格式和短格式的差別。短選項中也可以帶中橫線、也可以不帶中橫線。

根據選項長短和是否有橫線的情況,ps指令的選項可以分為以下3類:

  • BSD風格文法,必須不能以中橫線開頭;
  • SYSV風格文法,必須僅一個中橫線開頭;
  • GNU風格文法,必須以兩個中橫線開頭;
值得收藏-史上最全Linux ps指令詳解

不過linux ps指令的長選項并不多,而且幾乎每個長選項都有一個功能完全相同的短選項對應。在centos7環境運作如下指令可以見。

值得收藏-史上最全Linux ps指令詳解

在本文中我們将主要介紹BSD和SYSV兩種風格的ps指令選項。如果大家有對GNU風格的長選項使用的需求,那麼可以參考對應的短選項文法即可。需要注意的是GNU風格選項都是帶參數值的,例如--sid 1。

各風格的ps指令選項可以混合使用,比如:

值得收藏-史上最全Linux ps指令詳解

Linux ps指令解析SYSV和BSD風格選項時,會分别将每組字元串都解析成單獨的字母。以下三個執行個體,拆分前後的指令都是等價的。

值得收藏-史上最全Linux ps指令詳解

從示例中可以看出,當SYSV風格文法一個中橫線之後有多個字母選項時,拆分後需要給每一個字母前都加上一個中橫線。也就是說-elL轉換為-e -l -L,而不是轉換為-e l L。

從上面例子中也可以看出,ps指令選項除了有是否加中橫線的差別,字母大小寫也表現為不同的選項含義。英文字母一共26個,SYSV風格選項-A到-Z和-a到-z共52個,BSD風格選項A到Z和a到z共52個。于是ps指令就有一共104個指令選項可能性。

不同版本的ps指令選項的使用可能略有出入,本文主要使用主流的centos7上的procps-ng version 3.3.10版本來說明。在這104個指令選項中,未啟用的或曾經使用過現在廢棄的指令選項有如下40個,分别是A、B、C、D、E、F、G、I、J、K、P、Q、R、W、Y、b、d、i、y、z、-B、-D、-E、-I、-J、-K、-Q、-R、-S、-W、-X、-Y、-b、-h、-i、-k、-r、-v、-x和-z。

既然是未啟用或已廢棄,那麼運作帶這個選項的ps指令應該會報錯。試運作下大部分确實如此,不過也有幾個例外,比如ps -x指令就不報錯,可以正常輸出。這樣的例外選項一共有如下7個-S、-X、-h、-k、-r、-v和-x,本文第九節會給予說明。

這104個指令選項中的其餘64個選項就構成了linux ps指令的龐大指令選項體系,接下的内容就對他們分别給予介紹。

要檢視我們目前ps指令的版本,就用到V、-V這2個選項。

值得收藏-史上最全Linux ps指令詳解

為了本文中意思表達更加準确,這裡借用資料庫中的幾個概念。ps指令輸出結果,約定為結果集。結果集中的每一行,我們約定為記錄(record)。結果集或記錄中的每一列,我們約定為字段(field)。

三、Linux ps指令的記錄類選項

差不多每一個工程師使用ps指令時應該都有這樣的疑問, 使用ps aux時輸出結果中記錄行數要遠大于隻使用ps指令時(如下所示)。這其實會讓很多工程師在使用ps指令查找需要的程序時心裡很忐忑,會不會由于指令的選項使用不當導緻ps沒有列出所需要的程序資訊。正是這個原因,我們首先需要搞懂ps指令影響記錄行數的那些選項。

值得收藏-史上最全Linux ps指令詳解

3.1、all_processes選項

Linux ps指令的記錄類選項大概有20幾個之多。有些可以列出所有的程序資訊,有些按某種規則篩選顯示部分程序資訊。如今作業系統中awk、sed和grep這些shell文本處理指令的功能都十分強大,我們重點還是掌握ps指令中那些顯示所有程序資訊記錄的選項,其他ps指令過濾選項都可以通過shell文本處理指令(awk、sed和grep)間接實作。

Linux ps指令顯示所有程序資訊的選項隻有2個,即SYSV風格的-e和-A。相比之下,-e更容易記憶和書寫,請大家牢記這個-e選項。

大家知道,ps指令的所有資訊都是linux kernel生成,并通過/proc/目錄輸出給使用者空間的。在/proc/目錄下,每一個以數字開頭的目錄,就對應一個程序資訊。既然如此,通過如下指令便可一目了然。

值得收藏-史上最全Linux ps指令詳解

參數-e和-A顯示的程序記錄數确實和proc目錄下的所有程序目錄數一緻。

3.2、simple_select選項

Linux ps指令的simple_select選項一共5個,具體包括-a、-d、a、g和x。他們包括2個SYSV風格和3個BSD風格選項。2個SYSV風格和3個BSD風格的選項不能同時使用,否則會報錯。2個SYSV風格或3個BSD風格内部可以組合使用,具體的組合可能性有-ad、ga、ax、gx、agx。這裡值得注意的是這種字母組合選項絕對不是單字母選項篩選規則的簡單組合,ps指令給這幾種組合賦予了新的篩選規則。

Linux環境下的ps指令,會對BSD風格simple_select選項部分做2個特殊處理:

在原來的BSD風格simple_select情況下,再額外增加一個g選項;

如果已經有a、g和x三個選項都出現了,那麼就直接替換為-e選項;

按照這2個特殊處理規則,ps aux選項組合等價于ps auxg,等價于ps agx u,等價于ps -e u。

總結下來,ps指令simple_select選項隻有6種組合情況-a、-d、-ad、g、ga、gx。每一種選項都賦予一個位圖值。ps指令通過位圖計算來實作它的篩選規則。比如g選項的位圖值select_bits是0x0a0a,下面以g選項為例說明。

值得收藏-史上最全Linux ps指令詳解

關于8、4、2、1的含義(關于tty、session、tgid和euid字段含義參考第七節):

“8” tty值等于目前程序tty值的程序;

“4” tty值為空的程序;

“2” session值等于目前程序tgid(pid)值的程序;

“1” euid值等于目前程序euid值的程序;

很明顯“4”這位都缺失,1這位都存在,那麼g選項的含義就是:顯示所有tty值存在的且euid值等于目前程序euid值的程序。對此持懷疑态度的同學可以通過如下2個指令進行驗證。

值得收藏-史上最全Linux ps指令詳解

同樣的分析方法,其他幾個選項和選項組合的含義:

  • 選項-a含義:顯示所有tty值存在的且session值不等于目前程序tgid(pid)值的程序;
  • 選項-d含義:顯示所有session值不等于目前程序tgid(pid)值的程序;
  • 選項組合-ad含義:顯示所有tty值存在的或session值不等于目前程序tgid(pid)值的程序。換句話說,被過濾掉的是所有tty值為空的且session值等于目前程序tgid(pid)值的程序;
  • 選項組合ga(或選項a)含義:顯示所有tty值存在的程序;
  • 選項組合gx(或選項x)含義:顯示所有euid值等于目前程序euid值的程序;

3.3、selection_list選項

這類選項比較容易了解,都是根據程序的某個屬性值對程序進行篩選。他們大多需要一個選項的參數,而且也都有功能完全一樣的GNU風格的長選項對應。此類選項一共13個,主要分為如下幾組:

程序ID選項,查詢PID值為一個或幾個PID值範圍的程序資訊。

值得收藏-史上最全Linux ps指令詳解

程序會話(session)ID選項,有關SessionID可以參見8.1小節。

值得收藏-史上最全Linux ps指令詳解

使用者ID選項,參見8.7小節。

值得收藏-史上最全Linux ps指令詳解

使用者組ID選項,參見8.7小節。

值得收藏-史上最全Linux ps指令詳解

程序名稱選項,顯示符合目前程序名稱參數的程序。這裡需要注意,當程序名參數值字元串長度大于15時,隻是用其前15位作為比對條件,參見8.2小節

值得收藏-史上最全Linux ps指令詳解

程序終端(tty)選項

值得收藏-史上最全Linux ps指令詳解

這些選項不但可以單獨使用,還可以組合使用(如下所示)。需要注意的是這些選項之間的組合是邏輯或的關系,即或者符合-u選項條件或者符合-p選項條件。

值得收藏-史上最全Linux ps指令詳解

3.4、特殊選擇選項

當不希望結果中出現标題頁頭這一行資訊時,h選項可以隐藏ps輸出結果中的标題欄。

值得收藏-史上最全Linux ps指令詳解

如果我們隻希望列出運作中的R狀态和D狀态的程序,r 選項選中時将隻顯示其他篩選條件過濾後的結果集中的R和D狀态程序。幫助手冊上寫隻篩選R狀态是不正确的,這裡也包括D狀态程序的篩選。

值得收藏-史上最全Linux ps指令詳解

有時候如果我們需要顯示的程序記錄不好篩選,但是他的補集卻很容易篩選。那我們可以使用-N選項。選中此選項時,将以系統中所有程序(ps -e結果)為全集對前述條件篩選後的結果取補集,即隻顯示原來不顯示的記錄。下面的例子中,去掉标題欄一行資訊後,472等于456加16,說明全集等于本集加補集(如下示例所示)。

值得收藏-史上最全Linux ps指令詳解

3.5、記錄類選項的作用順序

本節前幾部分全面的介紹了記錄篩選類選項,本小節将對這些選項的綜合作用順序進行一個系統介紹。

記錄類選項是對/proc/目錄下的程序資訊逐條篩選過濾的:

  • 首先判斷是否有all_processes選項。如果有all_processes選項,則本條記錄被選擇。如果沒有all_processes選項,則繼續下一規則。
  • 其次判斷是否有simple_select選項。如果有simple_select選項,則使用simple_select選項規則判斷本條記錄是否被選中。如果沒有被simple_select選項選擇,則繼續下一條規則。
  • 然後判斷是否有selection_list選項。如果有selection_list選項,則使用selection_list選項判斷本條記錄是否被選中。如果沒有selection_list選項,則繼續下一條規則。
  • 然後判斷選項中是否有BSD風格的選項。如果有BSD風格選項,則使用simple_select類的選項g規則判斷本條記錄是否被選中。如果沒有BSD風格選項,則進入下一條規則。
  • 此時不論ps指令有SYSV風格選項還是僅無選項ps指令,都會使用一個新的simple_select選項位圖進行篩選過濾,位圖值為0xaa00。如果還沒有被選中,則徹底失去被選中的機會。位圖值0xaa00的意義是:所有tty值等于目前程序tty的且euid值等于目前程序euid值的程序。
  • 接下來再看是否有r選項。如果有r選項則以上5個環節被選中的記錄中,隻有R和D狀态的記錄才能被繼續選中。如果沒有r選項,則以上5個環節中被選中的記錄,都繼續被選中。
  • 最後看是否有-N選項,如果有-N選項則以上第6個環節選中的将不被選中,第6個環節未選中的将被選中。如果沒有-N選項,則以上第6個環節中被選中的記錄,還繼續被選中。
  • 選項h單獨生效,如果有h選項則取消結果集的标題欄,如果沒有h選項則标題欄保持輸出。

四、Linux ps指令輸出結果排序選項

上面一章介紹了記錄類選項的使用,了解了如何篩選符合我們要求的記錄集。如果我們需要對輸出結果進行排序,那麼ps指令也給我們提供了3個選項,分别是k、f和-H。

4.1、字段排序選項

選項k可以讓我們以某個字段為條件對輸出結果進行排序,并且還可以使用+-符号設定升序排序還是降序排序。

值得收藏-史上最全Linux ps指令詳解

選項k還可以使用多個字段同時對結果集排序,從輸出結果可以看到,先按ppid進行升序排序,ppid值相同時,再按rss值進行升序排序。

值得收藏-史上最全Linux ps指令詳解

4.2、樹形排序選項

每一個程序都有一個父程序,所有使用者空間的程序的最終父程序都是1号程序,所有核心空間的線程的最終父線程都是2号線程。這樣所有程序按照父子程序的關系就可以構成2個樹形結構。選項f和-H就是實作這個樹形排序功能的2個選項。

值得收藏-史上最全Linux ps指令詳解

從上面的結果中不難看出,選項f是使用ACSII碼對父子程序進行關聯,選項-H是使用tab空格對父子程序進行關聯。

五、Linux ps指令線程展開選項

前面章節主要是說明了如何篩選和顯示程序的資訊。同一個程序有時候還會起多個線程,同樣核心也在/proc/目錄下顯示了程序的線程資訊,如下所示。

值得收藏-史上最全Linux ps指令詳解

Linux ps同樣提供了一組選項可以将每個程序的線程資訊詳細展現,這組選項包括H、-L、-T、M、m和-m。在講解這些選項之前,我們先看一個小測試。

值得收藏-史上最全Linux ps指令詳解

同樣為了統計的準确,用h選項去掉标題欄資訊。其中最後一個486的值是ps -e h的記錄數,說明目前系統有486個程序。非常巧的是486恰巧等于1217減去731的值。從這裡我們可以了解到H、-L和-T這3個選項記錄數都是731,M、m和-m三個選項記錄數都是1217。找一個起了多線程的程序檢視下具體輸出内容。

值得收藏-史上最全Linux ps指令詳解

選項-L的輸出可以看到一共4行輸出結果,第一行PID等于LWP(線程ID)的值,說明是線程組的主線程(即程序)。其餘三個線程ID各不相同,但PID值都和主線程的PID值一樣,說明是同一線程組的普通線程。

第二組三個選項單純的顯示不便識别,我們這裡先引入一個後面講解的O選項,額外增加一個輸出值LWP。

值得收藏-史上最全Linux ps指令詳解

可以看到一共5行輸出結果,對照上面的輸出我們可以判斷出,第二組選項除了把線程組中的4個線程分别顯示之外,又額外增加了一行内容專門用于顯示這個線程組(即程序)的資訊。我們再回頭看前面的1271減去731等于486應該就很容易明白了。

在H、-L和-T之間,以及M、m和-m之間,輸出資訊也略有不同,不過這些都是資料項和格式的不同,後面有專門章節介紹。

六、Linux ps指令的字段選項

6.1、字段組合類通用選項

很多人在使用ps指令時都會注意到,在我們輸入不同的指令組合時,ps指令輸出結果中列的資料項并不統一。比如下面2個指令。

值得收藏-史上最全Linux ps指令詳解

Linux ps指令的aux選項組合輸出PID、%CPU、%MEM、RSS、TIME等資料項,ps指令的-el選項組合輸出PID、PPID、WCHAN、TIME、CMD等資料項。首先一個問題就是,ps指令一共有多少資料項可以輸出。這個問題很好回答,通過L選項很容易擷取,一共有168個資料輸出項。

值得收藏-史上最全Linux ps指令詳解

其次的一個問題就是,是什麼決定了ps aux指令輸出結果中恰恰包含USER、PID、%CPU、%MEM、VSZ、RSS、TTY、STAT、START、TIME和COMMAND這11個資料項呢。原因是ps指令中有一些選項用來對資料字段進行固定組合的作用。其中aux中的u選項就固定包含了以上11個資料輸出項,并且他們的顯示順序也已經固化在代碼中。

Linux ps指令這種字段組合類選項一共15個。其中6個選項用途比較廣泛,其餘9個選項都主要适合在查詢某一種問題時使用。

本小節先介紹6個通用選項:

面向使用者角度來顯示程序狀況,其中的%CPU、%MEM、VSZ和RSS字段都是非常常用的資訊。

值得收藏-史上最全Linux ps指令詳解

采用詳細格式顯示程序狀況,此類選項所顯示字段主要為一些常用字段資訊。

值得收藏-史上最全Linux ps指令詳解

采用完整格式顯示程序狀況,此類選項所顯示字段同樣為一些常用字段資訊。

值得收藏-史上最全Linux ps指令詳解

6.2、字段組合類專用選項

本小節先介紹9個适合特殊用途的專用選項:

采用作業(job)控制的格式顯示程序狀況,字段PPID、PID、PGID、SID和TPGID都是此選項的關鍵資訊。

值得收藏-史上最全Linux ps指令詳解

采用舊式的linux i386寄存器格式顯示程序狀況,很明顯此選項特點是STACKP、ESP和EIP這些寄存器資訊。

值得收藏-史上最全Linux ps指令詳解

Linux或sunos作業系統中會額外增加PSR字段的顯示,PSR字段是指目前程序被排程到的CPU核序号。

值得收藏-史上最全Linux ps指令詳解

采用程式信号的格式顯示程序狀況,此選項特色字段是PENDING、BLOCKED、IGNORED和CAUGHT字段。很顯然,當我們進行linux信号程式設計時,使用此選項非常有用。

值得收藏-史上最全Linux ps指令詳解

采用虛拟記憶體的角度顯示程序狀況,此選項特色字段包括MAJFL、TRS、DRS、RSS和%MEM。

值得收藏-史上最全Linux ps指令詳解

列印作業系統強制通路控制(SELinux)的安全标簽資訊,此選項特點是LABEL字段資訊。

值得收藏-史上最全Linux ps指令詳解

也許有人已經觀察到了,以上字段組合選項,不論哪個都會固定的有幾個字段總是出現,比如PID、TTY、TIME和CMD等。下面請大家先看一下這幾個例子。

值得收藏-史上最全Linux ps指令詳解

從以上例子中,我們可以得出幾個資訊。參數為BSD風格時,預設都會顯示PID、TTY、STAT、TIME和COMMAND這5個字段。參數為SYSV風格時,預設都會顯示PID、TTY、TIME和CMD這4個字段。ps指令無參數時預設為SYSV風格。

6.3、自定義字段選項

上一小節字段組合選項是ps指令為了一些常用場景固化在代碼中的固定資料項組合。但是如果以上所有組合都不滿足我們的要求,或者我們為了提升ps指令運作效率僅僅需要個别的資料項輸出。那麼我們可以通過-o或o選項來實作自定義資料項的輸出功能。比如我們對ps j這個指令字段組合的輸出資訊不滿意,我們自定義他的輸出。

值得收藏-史上最全Linux ps指令詳解

前文提到過,ps指令一共可以輸出168個字段,ps L指令可以顯示這168個字段的詳細情況。第一列小寫字母是-o選項的參數,可以通過逗号隔開。第二列大寫字母是ps指令輸出的結果集标題欄名稱。

盡管大部分情況下-o參數和标題欄都僅僅是大小寫的轉換關系,但也有不那麼完美的時候,以程序的執行指令字段為例。

值得收藏-史上最全Linux ps指令詳解

這個例子至少可以說明兩點,不同的說明符(specifier,-o選項參數)可能輸出同樣的标題欄。盡管标題欄一樣,但顯示的内容可能是有差別的。

有些說明符還提供縮寫,下表是ps指令有縮寫的說明符和縮寫的對應關系表,一共15個。

值得收藏-史上最全Linux ps指令詳解

有了說明符的縮寫之後,可以對自定義字段的輸出字段之間添加自定義分隔符。差別于以往ps指令各輸出字段都是使用空格作為分割,使用自定義分隔符之後将更友善使用shell資料處理指令進行解析。

值得收藏-史上最全Linux ps指令詳解

前文提到所有字段組合選項都預設包含4個或5字段。如果想在自定義字段組合時也預設添加一些常用字段,而同時又省去-o選項參數的輸入過程,那麼可以使用O或-O選項。

值得收藏-史上最全Linux ps指令詳解

這2個選項O或-O,會在自定義字段之前預設增加pid字段,在自定義字段之後預設增加state、tname、time和command字段。

七、Linux ps指令字段修飾選項

本節前面的選項都是決定輸出結果中字段的數量和順序,本小節将介紹幾個隻對輸出結果中某個字段進行修飾的選項。首先來看-w和w選項。

值得收藏-史上最全Linux ps指令詳解

這個執行個體說明,當螢幕不是很寬時,如果程序指令很長,預設情況下,會将指令超出螢幕的部分截取掉,這樣勢必會影響系統管理者調查問題,使用w或-w選項,就會将完整的程序指令資訊顯示,多出的部分換行顯示。有的時候為了效果好一點,建議我們可以多使用幾次w選項,比如ww、www或wwww。

接下來我們再來看一下c和e選項。

值得收藏-史上最全Linux ps指令詳解

選項u的COMMAND字段,預設會輸出程序路徑和執行參數資訊。從上面的例子可以看出,選項c可以使選項u的COMMAND字段更加精簡,隻保留程序名稱。選項e可以使選項u的COMMAND字段更加豐富,增加程序環境變量的相關内容。

當選項S被選中,ps指令在顯示如下6個字段資訊時,會将已經死亡的子程序資訊也包含計算在内,如果未選中S選項将不會計算這些已經死亡的子程序資訊 。快速同時執行如下2個指令,即可看出這6個字段值,選中S值後比之前有明顯增大。具體字段含義請參考8.5小節和8.6小節。

值得收藏-史上最全Linux ps指令詳解

Linux ps指令的字段中有個wchan字段(wchan相關含義參考8.8小節)。預設情況下ps指令會輸出wchan的符号資訊,如果希望輸出wchan的原始數值資訊,可以使用n選項。請比較如下2個指令,添加n選項前後第11個字段的輸出差别。除了wchan之外,選項n還可以将原本輸出user name的地方轉換為user id輸出。

值得收藏-史上最全Linux ps指令詳解

字段wchan的數值資訊和符号資訊的映射關系通過作業系統中一些System.map檔案完成,如果使用者需要使用自定義的System.map檔案,可以通過選項N或-n完成,如下示例。

值得收藏-史上最全Linux ps指令詳解

八、Linux ps指令常用字段

  前文提到linux ps一共最多可以輸出168個字段,通過ps L指令可擷取詳情。通過字段相關選項可以擷取符合用途的字段組合。為了讓大家對ps指令的了解更加深入,本節會深入介紹一些常用的輸出字段的含義。

  按照這些常用字段的内在關系,我們将分為以下八個小結介紹。

8.1、程序ID類字段

  程序ID類字段是ps指令字段中最基礎的一類。為了能更加形象的說明這些ID的關系和含義,請大家按照如下指令順序操作。

值得收藏-史上最全Linux ps指令詳解

對以上輸出結果的字段逐條說明:

字段tid表示程序的線程ID,可以看出每個線程的tid都不相同。

字段nlwp表示目前線程組中的線程個數,以上指令都是單線程程序,是以此值均為1。

字段pid表示程序ID,也可以看出每個程序的PID都不相同。

字段pgid表示程序組ID,上面的例子中除了和setsid結合的vmstat指令,其餘三組通過shell管道連接配接起來的指令的pgid都相同。比如tail、awk和nl指令的pgid都為1384,且pgid值為組内第一個指令tail的pid值;iostat、sed和fold指令的pgid都為1388,且pgid值為組内第一個指令iostat的pid值。

字段sid表示會話ID。上面的例子中最後一行是第三個登入終端的shell。第一個登入終端上的所有程序sid都相同,且為登入shell的pid值1351;除了和setsid結合的vmstat指令,第二個終端上的所有程序sid都相同,且為登入shell的pid值1394。

字段tpgid表示程序連接配接到的tty(終端)所在的前台程序組的ID。除了vmstat程序之外,第二個終端上的所有程序tpgid也都等于登入shell的pid值1394。但是第一個終端上的所有程序tpgid卻都等于第一個終端上又啟動的那個shell的程序id值1370。充分說明了tpgid值是連結着終端的前台程序組ID值。

字段ppid表示父程序ID。

最後我們再來解釋和vmstat結合的setsid,setsid就是使和它結合的vmstat脫離原來的會話,脫離之後pgid和sid都等于了vmstat程序的pid,同時父程序也由1号程序托管。此時也沒有了所依附的終端,tpgid統一等于-1。Linux上的所有守護程序的tpgid值都是-1。

  程序ID類字段的别名情況:字段spid和字段lwp是字段tid的别名,字段tgid是字段pid的别名,字段pgrp是字段pgid的别名,字段sess和字段session是字段sid的别名。

8.2、指令名字段

  指令名相關的字段一共有3組,如下所示。

值得收藏-史上最全Linux ps指令詳解

指令名字段的别名情況:字段comm和字段ucomm是字段ucmd的别名,字段args和字段command是字段cmd的别名。

建議大家掌握ucmd和cmd這2個字段,cmd為長指令名字段,ucmd為短指令名字段,可以了解為unadorned cmd(未加修飾的指令名)。

前文提到過如果程式名稱長度超過15位,ps指令的短指令名無法完整顯示16位及以上的部分。下面看一個小例子來說明這個問題。

值得收藏-史上最全Linux ps指令詳解

從上面的例子可以看出,當程式名稱超過15位時,确實短指令名無法顯示完整的程式名稱,隻顯示了15位。進一步檢視/proc/8040/目錄,可以發現如下資訊。

值得收藏-史上最全Linux ps指令詳解

查詢核心代碼,可以發現comm值取自核心struct task_struct結構體的comm屬性字段。

值得收藏-史上最全Linux ps指令詳解

這就告訴我們通過ps指令短指令字段無論如何都無法輸入超過15位的程式名稱,原因是核心資料結構原生就隻支援15個字元長度的程式名稱。

除此之外上面的例子還給我們另外一個啟示,如果通過使用SYSV風格的短指令名就可以滿足使用要求(如ps -el),那就盡量不要使用BSD風格的長指令名(如ps -e u,即ps aux)。長指令名需要依賴核心中健康的檔案系統,而當檔案系統工作不正常時,往往短指令名卻可以不受影響。是以我們在實際生産中偶爾會發現系統中有大量ps aux程序D住的情況。

8.3、程序狀态字段

  程序狀态類字段一共有三個,分别是s、state和stat,如下所示。

值得收藏-史上最全Linux ps指令詳解

 字段s和state互為别名,值為單位元組程序狀态。這裡重點介紹一下stat選項的多位元組程序狀态,檢視一下ps指令關于這個多位元組程序狀态的c語言代碼。

值得收藏-史上最全Linux ps指令詳解

根據以上源代碼,我們來逐條解釋:

字元'<'表示nice值小于0,nice值最小為-20。程序特性nice值允許程序間接的影響核心排程算法。所謂nice就是指對其他程序的謙讓程度,顯然比0越小就越不謙讓,比0越大就越謙讓。顧名思義,越謙讓的君子在CPU排程過程中占用CPU的時間會越少,反之不謙讓的程序相比較可能占用更多的CPU時間。是以字元'<'表示此程序可能在排程過程中獲得優勢。

字元'N'表示nice值大于0,nice值最大為19。是以字元'N'表示此程序可能在排程過程中不能獲得優勢。

字元'L'表示程序vm_lock值為真,即此程序有記憶體頁被鎖在記憶體中,這些記憶體頁不能通過換頁換出。

字元's'表示程序的tgid(pid)值等于程序的session(sid)值,這說明目前程序是會話的leader,參考8.1小節。

字元'l'表示程序中的線程數量大于1,這說明目前程序是一個多線程程式。

字元'+'表示程序的pgrp(pgid)值等于程序的tpgid前台程序組ID,這表示目前程序在前台程序組中。

8.4、時鐘(系統)時間類字段

  時鐘時間(系統時間)類字段,記錄了程序開始時間點和執行的時長資訊,這類字段一共有6組。其中4個記錄程序開始時間點,2個記錄程序執行時長資訊,示例如下。

值得收藏-史上最全Linux ps指令詳解

從自動化運維腳本的角度,lstart字段的輸出資訊格式更加規範便于解析,etimes字段作為一個正整數也可以直接使用。字段start_time是字段stime的别名。下面給一個使用的例子。

值得收藏-史上最全Linux ps指令詳解

字段lstart的輸出固定占用了2 2 6這5列資訊,這樣在其後的etimes字段也固定占用了第$7列。使用awk結合date指令很友善的就将程序開始時間轉化為時間戳格式。

8.5、CPU時間和使用率字段

  CPU時間和使用率類字段一共有5組,記錄了程序所消耗的CPU時間片和CPU使用率資訊,示例如下。

值得收藏-史上最全Linux ps指令詳解

字段bsdtime的輸出相比較cputime更加友善轉換為正整數的秒數。字段cp的機關是千分比,不能超過999。字段c是百分比,不能超過99。

  程序CPU時間類字段别名:字段atime和字段time是字段cputime的别名;字段util是字段c的别名;字段%cpu是字段pcpu的别名,但是%字元在crontab中使用并不友好,推薦使用pcpu。

下面來說明一下ps指令的CPU使用率的含義,先運作一個例子。

值得收藏-史上最全Linux ps指令詳解

從這個指令運作的結果可以看出bsdtime除以etimes的值轉換為百分比後,基本和pcpu的值相等。這就足以說明ps指令的CPU使用率字段名額是指從程序開始運作以來程序所耗費的CPU時間片占時鐘時間的百分比。有時候這個值大于100%,那是因為程序啟用了多線程,很多時候有多核在同時使用CPU時間片。

  看過top指令源碼可以知道,top指令預設是取最近3秒鐘程序所耗費的CPU時間片除以3秒鐘的百分比值。我們可以設想一種場景,如果一個程序已經運作了1年以上,平時都很穩定。但是剛剛就在十幾分鐘前突然運作大量線程,占用大量CPU資源。結果你在你剛剛登陸系統之前10秒鐘這些運作的線程都結束了。那麼你不論是通過top指令的CPU使用率名額,還是ps指令的CPU使用率名額都無法發現剛才作怪的這個線程的迹象。

8.6、程序記憶體相關字段

程序記憶體相關字段也ps指令字段中非常重要的一類,主要分為如下9組,示例如下。

值得收藏-史上最全Linux ps指令詳解
  • 字段vsz(virtual memory size)表示程序所申請的虛拟位址空間的記憶體大小,機關KB。在64位系統中,每個程序都有128Tb大小的堆記憶體虛拟位址空間的記憶體空間大小。vsz值并不反映程序占用的真正實體記憶體大小。
  • 字段rss(resident set size)表示程序真正占用了的實體記憶體大小,機關KB。
  • 字段pmem表示程序占用的實體記憶體大小(rss)占本機總實體記憶體大小百分比。
  • 字段trs(text resident set size)表示用于可執行代碼的實體記憶體大小,約等于程序的程式尺寸大小。
  • 字段drs(data resident set size)表示可執行代碼之外的記憶體大小,實際基本等于vsz減去trs的值。
  • 字段size表示如果程序交換到磁盤所需的交換空間大小。
  • 字段sz表示程序在實體頁面中的核心鏡像的大小。
  • 字段minflt表示此程序中發生的次缺頁異常的數量,下面詳細介紹。
  • 字段majflt表示此程序中發生的主缺頁異常的數量。

 程序記憶體相關字段别名:字段m_drs和字段dsiz是字段drs的别名,字段vsize是字段vsz的别名,字段m_size是字段sz的别名,字段rssize、字段rsz和字段sgi_rss是字段rss的别名,字段m_trs、字段trss和字段tsiz是字段trs的别名,字段%mem是字段pmem的别名,字段min_flt是字段minflt的别名,字段maj_flt和字段pagein是字段majflt的别名。

下面通過一個例子來加深對缺頁異常的了解。

值得收藏-史上最全Linux ps指令詳解

可以看出字段rss和字段minflt的比值趨近于4。作業系統管理記憶體的基本單元是4096位元組大小的頁框,當程序通路尚未有實體記憶體建立頁表映射關系的虛拟記憶體位址值時,會産生一次缺頁異常。在缺頁異常處理過程中會為虛拟記憶體頁配置設定一個實體記憶體頁并建立映射。是以每一次缺頁異常就會配置設定4096(4kb)位元組的實體記憶體,這樣rss和minflt的比值當然就是4了。如果配置設定之後又有釋放,後面再次配置設定,會使這個比值逐漸小于4。如果這個比值過于小,那我們就有充足理由懷疑使用者程式代碼在記憶體管理上存在重大問題。

8.7、程序憑證類字段

  程序憑證類字段一共有30多個,其中大部分可以彙總為如下表格。

值得收藏-史上最全Linux ps指令詳解

其中有些憑證是另外憑證的别名,比如uid是euid的别名,svuid是suid的别名,fsuid是fuid的别名。是以這些憑證字段簡單的可以歸納為如下4方面憑證:

  • 實際憑證 (real user ID):一般表示程序的建立者,屬于哪個使用者建立。
  • 有效憑證 (effective user ID):表示程序對于檔案和資源的通路權限,具備等同于哪個使用者的權限。
  • 保護憑證 (saved set-user-ID):set-user-ID的儲存ID。
  • 檔案系統憑證 (file-system user ID):已經基本廢棄。

8.8、WCHAN字段

WCHAN類字段一共3個nwchan、wchan和wname。WCHAN就是waiting channel的意思,程序正在休眠的核心函數的函數符号名稱。R狀态程序此字段值為“-”。

值得收藏-史上最全Linux ps指令詳解

字段wchan和wname都顯示的是核心函數的函數符号名稱資訊,預設隻顯示6個位元組。如果希望顯示完整的函數名稱,可以通過在字段名稱後加冒号再加寬度數值的方式顯示更豐富資訊,即wchan:25。

字段nwchan顯示的是核心函數符号的指針位址數值資訊。一個完整的64位的核心函數指針位址是一個16位的十六進制值,前10位固定為'ffffffff81',是以ps指令的nwchan字段隻顯示出了後6位的十六進制值。比如指針位址是ffffffff8124bb7e,那麼nwchan顯示24bb7e。如果後6位的高位有0,則省略掉0的顯示。

九、Linux ps指令選項容錯機制

Linux ps指令所有的選項和大多數字段都解釋過了,現在該說說文章開頭那個報錯的ps -axu了。

ps指令會提供一種選項容錯機制。當使用者輸入的是一個SYSV風格參數組合後,如果參數解析失敗,ps指令會繼續嘗試把同樣的字母組合都轉換為BSD風格再嘗試進行一次解析。比如ps -aux解析失敗後嘗試按ps aux解析,ps -x解析失敗後嘗試按ps x解析。當然了,如果再次按照BSD風格嘗試解析仍失敗,那ps指令會最終失敗報錯。

事實上,能有機會被ps指令容錯機制糾正的錯誤選項隻有這7個,-S、-X、-h、-k、-v、-r和-x。因為這些字母雖然沒有SYSV風格的選項,但是卻都有BSD風格的選項。

值得收藏-史上最全Linux ps指令詳解

最後說一下,沒有将BSD風格到SYSV風格的容錯機制,比如SYSV風格有-F選項,而BSD風格沒有F選項。運作指令ps F還是會報錯。

十、Linux ps指令綜合解析

10.1、常用選項摘要

本文對linux ps指令的104個短選項都進行了說明,其中隻有一部分選項比較常用,下面根據我的經驗推薦給大家重點關注:

  • 選項-e:顯示所有程序的記錄,記住這個參數就可以保證把目前系統的所有程序都輸出。需要篩選程序時,可以結合grep等文本處理指令實作目的。
  • 選項h:選中時可以隐藏輸出結果的标題欄資訊,在一些自動化腳本中使用此參數可以去除頁頭資訊。
  • 選項k:通過此選項可以實作對輸出結果的排序。
  • 選項-L:通過此選項可以把多線程的程序展開每個線程的細顆粒度。
  • 選項-l:或選項l,此選項可以列出程序的最基本資訊,包括s、pid、ppid、time和ucmd等字段資訊。
  • 選項u:此選項可以列出cpu使用率、mem使用率、rss記憶體等字段資訊。
  • 選項-o:或選項o,通過此選項可以自定義輸出符合自己需求的字段資訊。

Linux ps指令的168個輸出字段,我們也對大部分進行了介紹。下面根據經驗推薦給大家一些常用的關注。

值得收藏-史上最全Linux ps指令詳解

結尾

Linux ps指令博大精深,以上内容可能不一定完整。如果大家覺得文章中有任何補充,請加群回報資訊。如果你對ps指令使用還有其他疑問,也歡迎加群答疑。

繼續閱讀