歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux下的進程詳解

進程

進程是正在執行的程序實例。執行程序時,內核會將程序代碼載入虛擬內存,為程序變量分配空間,在內核中建立相應的數據結構,以記錄與進程有關的各種信息(比如,進程ID、用戶ID、組ID以及終止狀態等)

在內核看來,進程是一個個實體,內核必須在它們之間共享各種計算機資源。對於像內存這樣的受限資源來說,內核一開始會為進程分配一定數量的資源,並在進程的生命周期內,統籌該進程和整個系統對資源的需求,對這一分配進行調整。程序終止時,內核會釋放所有此類資源,供其他進程重新使用。其他資源(如CPU、網絡帶寬等)等屬於可再生資源,但必須在所有進程間平等共享。

進程的內存布局

邏輯上將一個進程劃分為以下幾個部分(也稱為段)

文本:程序的指令。

數據:程序使用的靜態變量。

堆:程序可從該區域動態分配額外內存。

棧:隨函數調用、返回而增減的一片內存,用於為局部變量和函數調用鏈接信息分配存儲空間。

創建進程和執行程序

進程可使用系統調用fork()來創建一個新進程。調用fork()的進程被稱為父進程,新創建的進程則被稱為子進程。內核通過對父進程的復制來創建子進程。子進程從父進程處繼承數據段、棧段以及堆段的副本後,可以修改這些內容,不會影響父進程的“原版”內容。(在內存中被標記為只讀的程序文本段則由父、子進程共享)

然後,子進程要麼去執行與父進程共享代碼中的另一組不同函數,或者,更為常見的情況是使用系統調用execve()去加載並執行一個全新程序。execve()會銷毀現有的文本段、數據段、棧段及堆段,並根據新程序的代碼,創建新段來替換它們。

進程ID和父進程ID

每一進程都有一個唯一的整數型進程標識符(PID).此外,每一進程還具有一個父進程標識符(PPID)屬性,用以標識請求內核創建自己的進程。

進程終止和終止狀態

可使用以下兩種方式之一來終止一個進程:其一,進程可使用_exit( )系統調用(或相關的exit()庫函數),請求退出;其二,向進程傳遞信號,將其"殺死”。無論以何種方式退出,進程都會生成“終止狀態”,一個非負小整數,可供父進程的wait()系統調用檢測。在調用_exit()的情況下,進程會指明自己的終止狀態。若由信號來“殺死”進程,則會根據導致進程“死亡”的信號類型來設置進程的終止狀態。(有時會將傳遞進_exit()的參數稱為進程的“退出狀態”,以示與終止狀態有所不同,後者要第指傳遞給_exit()的參數值,要麼表示“殺死”進程的信號。)

根據 慣例,終止狀態為0表示進程“功成身退”,非0則表示有錯誤發生。大多數shell會將前一執行程序的終止狀態保存於shell變量$?中。

進程的用戶和組標識符

每個進程都有一組與之相關的用戶ID(UID)和組ID(GID),如下所示

真實用戶ID和組ID:用來標識進程所屬的用戶和組。新進程從其父進程處繼承這些ID。登錄shell則會從系統密碼文件的相應字段中獲取其真實用戶的ID和組ID。

有效用戶ID和組ID:進程在訪問受保護資源(比如,文件和進程間通信對象)時,會使用這兩個ID來確定訪問權限。一般情況下,進程的有效ID與相應的真實ID值相同。

補充組ID:用來標識進程所屬的額外組。新進程從其父進程處繼承補充組ID。登錄shell則從系統組文件中獲取其補充組ID。

能力(Capabilities)

始於內核2.2,Linux把傳統上賦予超級用戶的權限劃分為一組相互獨立的單元(稱之為”能力“)。每次特權操作都與特定的能力相關,僅當進程具有特定能力時,才能執行相應操作。傳統意義上的超級用戶進程(有效用戶ID為0),則相應開啟了所有能力。

賦予某進程部分能力,使得其既能夠執行某些特權操作,又防止其執行其它特權級操作。

init進程

系統引導時,內核會創建一個名為init的特殊進程,即”所有進程之父",該進程的相應程序文件為/sbin/init。系統的所有進程不是由init(使用fork())"親自創建,就是由其後代進程創建。init進程的進程號永遠為1,且總是以超級用戶權限運行。誰都不能"殺死"init進程,只有關閉系統才能終止該進程。init的主要任務是創建並監控系統運行所需的的一系列進程。

守護進程

守護進程指的是具有特殊用途的進程,系統創建和處理此類進程的方式與其他進程相同,但以下特征是其所獨有的:

“長生不老”。守護進程通常在系統引導時啟動,直至系統關閉前,會一直“健在”。

守護進程在後台運行,且無控制終端供其讀取或寫入數據。

環境列表

每個進程都有一份環境列表,即在進程用戶空間內存中維護的一組環境變量。這份列表的每一元素都由一個名稱及其相關值組成。由fork()創建的新進程,會繼承父進程的環境副本。這也為父子進程間通信提供了一種機制。當進程調用exec()替換當前正在運行的程序時,新程序要麼繼承老程序的環境,要麼在exec()調用的參數中指定新環境並加以接收。

資源限制

每個進程都會消耗諸如打開文件、內存以及CPU時間之類的資源。使用系統調用setrlimit(),進程可為自己消耗的各類資源設定一個上限。此類資源限制的每一項均有兩個相關值:軟限制限制了進程可以消耗的資源總量,硬限制是軟限制的調整上限。非特權進程在針對特定資源調整軟限制值時,可將其設置為0到相應硬限制值之間的任意值,但硬限制值則只能調低,不能調高。

由fork()創建的新進程,會繼承其父進程對資源限制的設置。

使用unlimit命令可調整shell的資源限制。

Copyright © Linux教程網 All Rights Reserved