1.1 Linux進程管理
進程管理是操作系統(tǒng)的最重要的功能之一。有效率的進程管理能保證一個程序平穩(wěn)而高效地運行。
Linux的進程管理與UNIX的進程管理相似。它包括進程調(diào)度、中斷處理、信號、進程優(yōu)先級、上下文切換、進程狀態(tài)、進度內(nèi)存等。
在本節(jié)中,我們將描述Linux進程管理的基本原理的實現(xiàn)。它將更好地幫助你理解Linux內(nèi)核如何處理進程及其對系統(tǒng)性能的影響。
1.1.1 什么是進程?
一個進程是一個運行在處理器的程序的一個實例。該進程使用Linux內(nèi)核能夠處理的任何資源來完成它的任務(wù)。
所有運行在Linux操作系統(tǒng)中的進程都被task_struct結(jié)構(gòu)管理,該結(jié)構(gòu)同時被叫作進程描述。一個進程描述包含一個運行進程所有的必要信息,例如進程標(biāo)識、進程屬性和構(gòu)建進程的資源。如果你了解該進程構(gòu)造,你就能理解對于進程的運行和性能來說,什么是重要的。圖1-2展示了進程結(jié)構(gòu)相關(guān)的進程信息概述。
圖1-2task_struct結(jié)構(gòu)體
1.1.2 進程的生命周期
每一個進程都有其生命周期,例如創(chuàng)建、運行、終止和消除。這些階段會在系統(tǒng)啟動和運行中重復(fù)無數(shù)次。因此,進程的生命周期對于其性能的分析是非常重要的。
圖1-3展示了經(jīng)典的進程生命周期。
圖1-3經(jīng)典的進程生命周期
當(dāng)一個進程創(chuàng)建一個新的進程,進程的創(chuàng)建進程(父進程)調(diào)用 一個fork()系統(tǒng)調(diào)用。當(dāng)fork()系統(tǒng)調(diào)用被調(diào)用,它得到該新創(chuàng)建進程(子進程)的進程描述并調(diào)用一個新的進程id。它復(fù)制該值到父進程進程描述到子進程中。此時整個的父進程的地址空間是沒有被復(fù)制的;父子進程共享相同的地址空間。
exec()系統(tǒng)調(diào)用復(fù)制新的程序到子進程的地址空間。因為父子進程共享地址空間,寫入一個新的程序的數(shù)據(jù)會引起一個分頁錯誤。在這種情況下,內(nèi)存會分配新的物理內(nèi)存頁給子進程。
這個推遲的操作叫作寫時復(fù)制。子進程通常運行他們自己的程序而不是與父進程運行相同的程序。這個操作避免了不必要的開銷,因為復(fù)制整個地址空間是一個非常緩慢和效率低下的操作,它需要使用大量的處理器時間和資源。
當(dāng)程序已經(jīng)執(zhí)行完成,子進程通過調(diào)用exit()系統(tǒng)調(diào)用終止。exit()系統(tǒng)調(diào)用釋放進程大部分的數(shù)據(jù)并通過發(fā)送一個信號通知其父進程。此時,子進程是一個被叫作僵尸進程的進程(參閱page 7的“Zombie processes”)。
子進程不會被完全移除直到其父進程知道其子進程的調(diào)用wait()系統(tǒng)調(diào)用而終止。當(dāng)父進程被通知子進程終止,它移除子進程的所有數(shù)據(jù)結(jié)構(gòu)并釋放它的進程描述。
1.1.3 線程
一個線程是一個單獨的進程生成的一個執(zhí)行單元。它與其他的線程并行地運行在同一個進程中。各個線程可以共享進程的資源,例如內(nèi)存、地址空間、打開的文件等等。它們能訪問相同的程序數(shù)據(jù)集。線程也被叫作輕量級的進程(Light Weight Process,LWP)。因為它們共享資源,所以每個線程不應(yīng)該在同一時間改變它們共享的資源?;コ獾膶崿F(xiàn)、鎖、序列化等是用戶程序的責(zé)任。
從性能的角度來說,創(chuàng)建線程的開銷比創(chuàng)建進程少,因數(shù)創(chuàng)建一個線程時不需要復(fù)制資源。另一方面,進程和線程擁在調(diào)度算法上有相似的特性。內(nèi)核以相似的方式處理它們。
圖1-4 進程和線程
在現(xiàn)在的Linux實現(xiàn)中,線程支持UNIX的可移植操作系統(tǒng)接口(POSIX)標(biāo)準庫。在Linux操作系統(tǒng)中有幾種可用的線程實現(xiàn)。以下是廣泛使用的線程庫:
LinuxThreads
LinuxThreads自從Linux內(nèi)核2.0起就已經(jīng)被作為默認的線程實現(xiàn)。LinuxThreads的一些實現(xiàn)并不符合POSIX標(biāo)準。Native POSIX Thread Library(NPTL)正在取代LinuxThreads。LinuxThreads在將來的Linux企業(yè)發(fā)行版中將不被支持。
Native POSIX Thread Libary(NPTL)
NPTL最初是由紅帽公司開發(fā)的。NPTL與POSIX更加兼容。通過Linux內(nèi)核2.6的高級特性,例如,新的clone()系統(tǒng)調(diào)用、信號處理的實現(xiàn)等等,它具有比LinuxThreads更高的性能和伸縮性。
NPTL與LinuxThreads有一些不兼容。一個依賴于LinuxThreads的應(yīng)用可能不能在NPTL實現(xiàn)中工作。
Next Generation POSIX Thread(NGPT)
NGPT是一個IBM開發(fā)的POSIX線程庫?,F(xiàn)在處于維護階段并且在未來也沒有開發(fā)計劃。
使用LD_ASSUME_KERNEL環(huán)境變量,你可以選擇在應(yīng)用中使用哪一個線程庫。
1.1.4 進程優(yōu)先級和nice值
進程優(yōu)先級是一個數(shù)值,它通過動態(tài)的優(yōu)先級和靜態(tài)的優(yōu)先級來決定進程被CPU處理的順序。一個擁有更高進程優(yōu)先級的進程擁有更大的機率得到處理器的處理。
內(nèi)核根據(jù)進程的行為和特性使用試探算法,動態(tài)地調(diào)整調(diào)高或調(diào)低動態(tài)優(yōu)先級。一個用戶進程可以通過使用進程的nice值間接改變靜態(tài)優(yōu)先級。一個擁有更高靜態(tài)優(yōu)先級的進程將會擁有更長的時間片(進程能在處理上運行多長時間)。
Linux支持從19(最低優(yōu)先級)到-20(最高優(yōu)先級)的nice值。默認值為0。把程序的nice值修改為負數(shù)(使進程的優(yōu)先級更高),需要以root身份登陸或使用su命令以root身份執(zhí)行。
1.1.5 上下文切換
在進程運行過程中,進程的運行信息被保存于處理器的寄存器和它的緩存中。正在執(zhí)行的進程加載到寄存器中的數(shù)據(jù)集被稱為上下文。為了切換進程,運行中進程的上下文將會被保存,接下來的運行進程的上下文將被被恢復(fù)到寄存器中。進程描述和內(nèi)核模式堆棧的區(qū)域?qū)脕肀4嫔舷挛?。這個切換被稱為上下文切換。過多的上下文切換是不受歡迎的,因為處理器每次都必須清空刷新寄存器和緩存,為新的進程制造空間。它可能會引起性能問題。
圖1-5 說明了上下文切換如何工作。
圖1-5 上下文切換
1.1.6 中斷處理
中斷處理是優(yōu)先級最高的任務(wù)之一。中斷通常由I/O設(shè)備產(chǎn)生,例如網(wǎng)絡(luò)接口卡、鍵盤、磁盤控制器、串行適配器等等。中斷處理器通過一個事件通知內(nèi)核(例如,鍵盤輸入、以太網(wǎng)幀到達等等)。它讓內(nèi)核中斷進程的執(zhí)行,并盡可能快地執(zhí)行中斷處理,因為一些設(shè)備需要快速的響應(yīng)。它是系統(tǒng)穩(wěn)定的關(guān)鍵。當(dāng)一個中斷信號到達內(nèi)核,內(nèi)核必須切換當(dāng)前的進程到一個新的中斷處理進程。這意味著中斷引起了上下文切換,因此大量的中斷將會引起性能的下降。
在Linux的實現(xiàn)中,有兩種類型的中斷。硬中斷是由請求響應(yīng)的設(shè)備發(fā)出的(磁盤I/O中斷、網(wǎng)絡(luò)適配器中斷、鍵盤中斷、鼠標(biāo)中斷)。軟中斷被用于處理可以延遲的任務(wù)(TCP/IP操作,SCSI協(xié)議操作等等)。你可以在/proc/interrupts文件中查看硬中斷的相關(guān)信息。
在多處理器的環(huán)境中,中斷被每一個處理器處理。綁定中斷到單個的物理處理中能提高系統(tǒng)的性能。更多的細節(jié),請參閱4.4.2,“CPU的中斷處理親和力”。
1.1.7 進程狀態(tài)
每一個進程擁有自己的狀態(tài),狀態(tài)表示了進程當(dāng)前在發(fā)生什么。
在進程的執(zhí)行期間進程的狀態(tài)會發(fā)生改變。一些進程的狀態(tài)如下:
TASK_RUNNING
在此狀態(tài)下,表示進程正在CPU中運行或在隊列中等待運行(運行隊列)。
TASK_STOPPED
在此狀態(tài)下的進程被某些信號(如SIGINT,SIGSTOP)暫停。進程正在等待通過一個信號恢復(fù)運行,例如SIGCONT。
TASK_INTERRUPTIBLE
在此狀態(tài)下,進程被暫停并等待一個某些條件狀態(tài)的到達。如果一個進程處于TASK_INTERRUPTIBLE狀態(tài)并接收到一個停止的信號,進程的狀態(tài)將會被改變并中斷操作。一個典型的TASK_INTERRUPTIBLE狀態(tài)的進程的例子是一個進程等待鍵盤中斷。
TASK_UNINTERRUPTIBLE
與TASK_INTERRUPTIBLE相似。當(dāng)一個進程處于?TASK_UNINTERRUPTIBLE狀態(tài)可以被中斷,向處于TASK_UNINTERRUPTIBLE狀態(tài)的進程發(fā)送一個信號不會發(fā)生任何操作。一個TASK_UNINTERRUPTIBLE進程的典型的例子是等待磁盤I/O操作。
TASK_ZOMBIE
當(dāng)一個進程調(diào)用exit()系統(tǒng)調(diào)用退出后,它的父進程應(yīng)該知道該進程的終止。處于TASK_ZOMBIE狀態(tài)的進程會等待其父進程通知其釋放所有的數(shù)據(jù)結(jié)構(gòu)。
圖1-6 進程狀態(tài)
僵尸進程
當(dāng)一個進程接收到一個信號而終止,它在結(jié)束自己之前,通常需要一些時間來結(jié)束所有的任務(wù)(例如關(guān)閉打開的文件)。在這個通常非常短暫的時間內(nèi),該進程就是一個僵尸進程。
進程已經(jīng)完成所有的關(guān)閉任務(wù)后,它會向父進程報告其即將終止。有些時候,一個僵尸進程不能把自己終止,這將會引導(dǎo)它的狀態(tài)顯示為z(zombie)。
使用kill命令來關(guān)閉這樣的一個進程是不可能的,因為該進程已經(jīng)被認為已經(jīng)死掉了。如果你不能清除僵尸進程,你可以結(jié)束其父進程,然后僵尸進程也隨之消失。但是,如果父進程為init進程,你不能結(jié)束它。init進程是一個非常重要的進程,因此可能需要重啟系統(tǒng)來清除僵尸進程。
1.1.8 進程內(nèi)存段
進程使用其自身的內(nèi)存區(qū)域來執(zhí)行工作。工作的變化根據(jù)情況和進程的使用而決定。進程可以擁有不同的工作量特性和不同的數(shù)據(jù)大小需求。進程必須處理各種數(shù)據(jù)大小。為了滿足需求,Linux內(nèi)核為每個進程使用動態(tài)申請內(nèi)存的機制。進程內(nèi)存分配的數(shù)據(jù)結(jié)構(gòu)如圖1-7所示。
圖1-7 進程地址空間
進程內(nèi)存區(qū)由以下幾部分組成:
Text段
該區(qū)域用于存儲運行代碼。
Data段
數(shù)據(jù)段包括三個區(qū)域。
– Data:該區(qū)域存儲已被初始化的數(shù)據(jù),如靜態(tài)變量。– BSS:該區(qū)域存儲初始化為0的數(shù)據(jù)。數(shù)據(jù)被初始化為0。– Heap:該區(qū)域用于根據(jù)需求使用malloc()動態(tài)申請的內(nèi)存。堆向高地址方向增長。
Stack段
該區(qū)域用于存儲局部變量、函數(shù)參數(shù)和返回函數(shù)的地址。棧向低地址方向增長。
用戶進程的地址空間內(nèi)存分布可以使用pmap命令來查看。你可以使用ps命令來查看內(nèi)存段的大小??梢詤㈤?.3.10的“pmap”,“ps和pstree”。
1.1.9 Linux CPU調(diào)度
任何的計算機的基本功能都非常簡單,就是計算。為了能夠計算,它意味著必須管理計算資源或處理器和計算任務(wù),也就是我們所知道的線程或進程。感謝Ingo Molnar的巨大貢獻,Linux內(nèi)核使用一個O(1)的算法代替以前的O(n)的CPU調(diào)度算法。O(1)指的是一種靜態(tài)的算法,意味著選擇一個進程并執(zhí)行所花費的時間是一個常數(shù),不管進程的數(shù)量的大小。
新的調(diào)度算法的擴展性非常好,不管進程的數(shù)量或者處理器的數(shù)量是多少,系統(tǒng)的開銷都是非常少的。該算法使用兩個進程優(yōu)先級數(shù)組:
active(活動的)
expired(過期的)
調(diào)度器根據(jù)進程的優(yōu)先級和優(yōu)先攔截率為進程分配時間片,然后進程以優(yōu)先級順序放置到active數(shù)組內(nèi)。當(dāng)進程時間片耗盡,進程申請一個新的時間片并放置到expired數(shù)組內(nèi)。當(dāng)active數(shù)組中的所有進程的時間片耗盡,這兩個數(shù)組進行切換,重新運行該算法。對于一般的交互式進程(相對于實時進程),擁有高優(yōu)先級的進程通常比低優(yōu)先級的進程得到更長的時間片和更多的計算時間,但這并不表示低優(yōu)先級的進程會被完全忽略(餓死)。該算法的優(yōu)勢是為擁有大量線程和進程并擁有多處理器的企業(yè)級環(huán)境提升Linux內(nèi)核的擴展性。該O(1)的新CPU調(diào)度器是為內(nèi)存2.6設(shè)計的,但是現(xiàn)在已經(jīng)移植到2.4系列中。圖1-8說明了Linux CPU如何調(diào)度工作。
圖1-8 Linux內(nèi)核2.6 O(1)調(diào)度器
新調(diào)度器的另一個顯著改進是支持非一致性內(nèi)存架構(gòu)(NUMA)和對稱多線程處理器,例如Intel超線程技術(shù)。
改進后的NUMA支持確保只有某個節(jié)點過載時,負載平衡才會跨越某個NUMA節(jié)點。這個機制確保了在NUMA系統(tǒng)相對比較緩慢的擴展鏈接流量的最小化。盡管每個調(diào)度節(jié)拍時負載平衡會遍歷調(diào)度域群組中的處理器,但只有在節(jié)點過載并請求負載平衡時,負載才會跨越調(diào)度域轉(zhuǎn)移。
圖1-9 O(1)CPU調(diào)度器結(jié)構(gòu)
-
處理器
+關(guān)注
關(guān)注
68文章
19404瀏覽量
230770 -
Linux
+關(guān)注
關(guān)注
87文章
11342瀏覽量
210140 -
線程
+關(guān)注
關(guān)注
0文章
505瀏覽量
19725
原文標(biāo)題:運維架構(gòu)師進階:Linux進程管理
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論