進程結構和內存布局


【摘自《Linux/Unix系統編程手冊》】

 

進程和程序

進程(process)是一個可執行程序(program)的實例。

程序是包含了一系列信息的文件,這些信息描述了如何在運行時創建一個進程,包含如下內容:

  • 二進制格式標識:每個程序文件都包含用於描述可執行文件格式的元信息(metainformation)。
  • 機器語言指令:對程序算法進行編碼。
  • 程序入口地址:標識程序開始執行時的起始指令位置。
  • 數據:程序文件包含的變量初始值和程序使用的字面常量值(比如字符串)。
  • 符號表及重定位表:描述程序中函數和變量的位置及名稱。這些表格有多種用途,其中包含調試和運行時的符號解析(動態鏈接)。
  • 共享庫和動態鏈接信息:程序文件所包含的一些字段,列出了程序運行時需要使用的共享庫,以及加載共享庫的動態鏈接器的路徑名。
  • 其它信息:程序文件還包含許多其它信息,用以描述如何創建進程。

從內核角度看,進程由用戶內存空間和一系列內核數據結構組成,其中用戶內存空間包含了程序代碼及代碼所使用的變量,而內核數據結構則用於維護進程狀態信息。

記錄在內核數據結構中的信息包括許多與進程相關的標識號、虛擬內存表、打開文件的描述符表、信號傳遞及處理的有關信息、進程資源使用及限制、當前工作目錄和大量的其它信息。

 

每個進程都有一個進程號(PID),進程號是一個正數,用以唯一標識系統中的某個進程。

Linux內核限制進程號需小於等於32767。新進程創建時,內核會按順序將下一個可用的進程號分配給其使用。每當進程號達到32767的限制時,內核將重置進程號計數器,以便從小整數開始分配。

(實際上,一旦進程號達到32767,會將進程號計數器重置為300,而不是1。因為低數值的進程號為系統進程和守護進程所長期占用。)

在Linux2.4版本及更早的版本,進程號的上限是32767,有內核常量PID_MAX所定義。在Linux2.6中,情況有所改變,盡管進程號的默認上限仍為32767,但可以通過Linux系統中特有的/proc/sys/kernel/pid_max文件來進行調整(其值=最大進程號+1)。在32位平台中,pid_max文件的最大值為32768,但是在64位平台中,該文件的最大值可以高達222(約400萬),系統可能容納的進程數量會非常龐大。

 

每個進程都有一個創建自己的進程,每個進程的父進程號屬性反應了系統上所有進程間的樹狀關系。每個進程的父進程又有自己的父進程,以此類推,回溯到1號進程--init進程,即所有進程的始祖。

如果子進程的父進程終止,則子進程就會變成“孤兒”,init進程隨即將收養該進程。

 

進程內存布局

每個進程所分配的內存由很多部分組成,通常稱之為“段(segment)”:

  • 文本段:包含了進程運行的程序機器語言指令。文本段具有只讀屬性,以防止進程通過錯誤指針意外修改自身指令。因為多個進程可同時運行同一程序,所以又將文本段設為可共享,這樣,一份程序代碼的拷貝可以映射到所有這些進程的虛擬地址空間中。
  • 初始化數據段:包含顯示初始化的全局變量和靜態變量。當程序加載到內存時,從可執行文件中讀取這些變量的值。
  • 未初始化數據段:包含了未進行顯示初始化的全局變量和靜態變量。程序啟動之前,系統將本段內所有內存初始化為0。出於歷史原因,此段常被稱為BSS段,這源於老版本的匯編語言助記符“block started by symbol”。將經過初始化的全局變量和靜態變量與未初始化的全局變量和靜態變量分開存放,其主要原因在於程序在磁盤上存儲時,沒有必要為未經初始化的變量分配存儲空間。相反,可執行文件只需記錄未初始化數據段的位置及所需大小,直到運行時再由程序加載器來分配空間。
  • (stack):是一個動態增長和收縮的段,有棧幀(stack frames)組成。系統會為每個當前調用的函數分配一個棧幀。棧幀中存儲了函數的局部變量(所謂自動變量)、實參和返回值。
  • (heap):是可在運行時(為變量)動態進行內存分配的一塊區域。堆頂端稱為program break。

對於初始化和未初始化的數據段而言,不太常用、但表達更清晰的稱為分別是用戶初始化數據段(user-initialized data segment)和零初始化數據段(zero-initialized data segment)。

在大多數Unix(包括Linux)中的C語言編程環境提供了3個全局符號(symbol):etext、edata、end,可以在程序中使用這些符號以獲取相應程序文本段、初始化數據段和非初始化數據段結尾處下一字節的地址。

使用這些符號,必須顯式聲明如下:

extern char etext, edata, end; // For example, &etext gives the address of the end of the program text / start of initialized data

圖中標灰的區域表示這些范圍在進程虛擬地址空間中不可用,也就是說,沒有為這些區域創建頁表(page table)。

 

虛擬內存管理

Linux采用了虛擬內存管理技術。該技術利用了大多數程序的一個典型特征,即訪問局部性(locality of reference),以求高效使用CPU和RAM(物理內存)資源。

大多數程序都展現了兩種類型的局部性:

  • 空間局部性(Spatial locality):是指程序傾向於訪問在最近訪問過的內存地址附近的內存(由於指令是順序執行的,且有時會按順序處理數據結構)。
  • 時間局部性(Temporal locality):是指程序傾向於在不久的將來再次訪問最近剛訪問過的內存地址(由於循環)。

正是由於訪問局部性特征,使得程序即便僅有部分地址空間存在於RAM中,依然可能得以執行。

 

虛擬內存的規划之一是將每個程序使用的內存分割成小型的、固定大小的“頁(page)”單元。相應地,將RAM划分成一系列與虛存頁尺寸相同的頁幀。任一時刻,每個程序僅有部分頁需要駐留在物理內存頁幀中。這些頁構成了所謂的駐留集(resident set)。程序未使用的頁拷貝保存在交換區(swap area)內--這是磁盤空間中的保留區域,作為計算機RAM的補充--僅在需要時才會載入物理內存。若進程欲訪問的頁面目前並未駐留在內存中,將會發生頁面錯誤(page fault),內核即刻掛起進程的執行,同時從磁盤中將該頁面載入內存。(程序可調用sysconf(_SC_PAGESIZE)來獲取系統虛擬內存的頁面大小)

為支持這一組織方式,內核需要為每個進程維護一張頁表(page table)。該頁表描述了每頁在進程虛擬地址空間(virtual address space)中的位置(可為進程所用的所有虛擬內存頁面的集合)。頁表中的每個條目要么指出一個虛擬頁面在RAM中的所在位置,要么表明其當前駐留在磁盤上。

 

在進程虛擬地址空間中,並非所有的地址范圍都需要頁表條目。通常情況下,由於可能存在大段的虛擬地址空間並未投入使用,故而也無必要為其維護相應的頁表條目。若進程試圖訪問的地址並無頁表條目與之對應,那么進程將受到一個SIGSEGV信號。

 

由於內核能夠為進程分配和釋放頁(和頁表條目),所以進程的有效虛擬地址范圍在其生命周期中可以發生變化。這可能會發生於如下場景:

  • 由於棧向下增長超出之前曾達到的位置。
  • 當在堆中分配或釋放內存時,通過調用brk()、sbrk()或malloc函數族來提升program break的位置。
  • 當調用shmat()連接System V共享內存區時,或者當調用shmdt()脫離共享內存區時。
  • 當調用mmap()創建內存映射時,或者當調用munmap()解除內存映射時。

 

虛擬內存管理是使進程的虛擬地址空間與RAM物理地址空間隔離開來,這帶來許多優點:

  •  進程與進程、進程與內核相互隔離,所以一個進程不能讀取或修改另一個進程或內核的內存。這是因為每個進程的頁表條目指向RAM(或交換區)中截然不同的物理頁面集合。
  • 適當情況下,兩個或更多進程能夠共享內存。這是由於內核可以使不同進程的頁表條目指向相同的RAM頁。內存共享常發生於如下兩種場景:
  1. 執行同一程序的多個進程,可共享一份(只讀的)程序代碼副本。當多個程序執行相同的程序文件(或加載相同的共享庫)時,會隱式地實現這一類型的共享。
  2. 進程可以使用shmget()和mmap()系統調用顯示地請求與其他進程共享內存區。這么做是出於進程間通信的目的。
  • 便於實現內存保護機制:也就是說,可以對頁表條目進行標記,以表示相關頁面內容是可讀、可寫、可執行亦或是這些保護措施的組合。多個進程共享RAM頁面時,允許每個進程對內存采取不同的保護措施。例如:一個進程可能以只讀方式訪問某頁面,而另一進程則以讀寫方式訪問同一頁面。
  • 程序員和編譯器、鏈接器之類的工具無需關注程序在RAM中的物理布局。
  • 因為需要駐留在內存中的僅是程序的一部分,所以程序的加載和運行都很快。而且,一個進程所占用的內存(即虛擬內存大小)能夠超出RAM的容量。

虛擬內存管理的最后一個優點是:由於每個進程使用的RAM減少了,RAM中同時可以容納的進程數量就增多了。這增大了如下事件的概率:在任一時刻,CPU都可執行至少一個進程,因而往往也會提高CPU的利用率。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM