Linux程序位址空間與虛擬記憶體

2021-07-03 17:32:32 字數 3358 閱讀 4111

分類: unix/linux

unix環境高階程式設計

2013-10-14 15:52

489人閱讀收藏 

舉報32位機器上linux

作業系統中的程序的位址空間大小是4g,其中0-3g是使用者空間,3g-4g是核心空間。程序的位址空間存在於虛擬記憶體中。虛擬記憶體不能被禁用。

程序位址空間

程序位址空間分為核心空間和使用者空間  

因為每個程序可以通過系統呼叫進入核心,因此,linux核心由系統內的所有程序共享。於是,從具體程序的角度來看,每個程序可以擁有4g位元組的虛擬空間。

a.正文段。這是由cpu執行的機器指令部分。通常,正文段是可共享的,所以即使是經常執行的程式(如文字編輯程式、c編譯程式、shell等)在儲存器中也只需要有乙個副本,另外,正文段常常是唯讀的,以防止程式由於意外事故而修改器自身的指令。

b.初始化資料段。通常將此段稱為資料段,它包含了程式中需賦初值的變數。例如,c程式中任何函式之外的說明:

int maxcount = 99;(全域性變數)

c.非初始化資料段。通常將此段稱為bss段,這一名稱**於早期匯程式設計序的乙個操作,意思是"block started by symbol",在程式開始執行之前,核心將此段初始化為0。函式外的說明:

long sum[1000];

使此變數存放在非初始化資料段中。

d.棧。自動變數以及每次函式呼叫時所需儲存的資訊都存放在此段中。每次函式呼叫時,其返回位址、以及呼叫者的環境資訊(例如某些機器暫存器)都存放在棧中。然後,新被呼叫的函式在棧上為其自動和臨時變數分配儲存空間。通過以這種方式使用棧,c函式可以遞迴呼叫。

e.堆。通常在堆中進行動態儲存分配。由於歷史上形成的慣例,堆位於非初始化資料段頂和棧底之間。

從上圖我們看到棧空間是下增長的,堆空間是從下增長的,他們會會碰頭呀?一般不會,因為他們之間間隔很大

核心態和使用者態

當乙個任務(程序)執行系統呼叫而陷入核心**中執行時,我們就稱程序處於核心執行態(或簡稱為核心態)。此時處理器處於特權級最高的(0級)核心**中執行。當程序處於核心態時,執行的核心**會使當前程序的核心棧。每個程序都有自己的核心棧。當程序在執行使用者自己的**時,則稱其處於使用者執行態(使用者態)。即此時處理器在特權級最低的(3級)使用者**中執行。當正在執行使用者程式而突然被中斷程式中斷時,此時使用者程式也可以象徵性地稱為處於程序的核心態。因為中斷處理程式將使用當前程序的核心棧。這與處於核心態的程序的狀態有些類似。

核心空間中存放的是核心**和資料,而程序的使用者空間中存放的是使用者程式的**和資料。不管是核心空間還是使用者空間。

在linux作業系統中,每個程序都通過乙個task_struct的結構體描敘,每個程序的位址空間都通過乙個mm_struct描敘,c語言中的每個段空間都通過vm_area_struct表示,他們關係如下 :

當執行乙個程式時,作業系統需要建立乙個程序,這個程序和程式之間都幹了些什麼呢?

當乙個程式被執行時,該程式的內容必須被放到程序的虛擬位址空間,對於可執行程式的共享庫也是如此。可執行程式並非真正讀到物理記憶體中,而只是鏈結到程序的虛擬記憶體中。

當乙個可執行程式對映到程序虛擬位址空間時,一組vm_area_struct資料結構將被產生。每個vm_area_struct資料結構表示可執行印象的一部分;是可執行**,或是初始化的資料,以及未初始化的資料等。

linux作業系統是通過sys_exec對可執行檔案進行對映以及讀取的,有如下幾步:

1.建立一組vm_area_struct

2.圈定乙個虛擬使用者空間,將其起始結束位址(elf段中已設定好)儲存到vm_start和vm_end中。

3.將磁碟file控制代碼儲存在vm_file中

4.將對應段在磁碟file中的偏移值(elf段中已設定好)儲存在vm_pgoff中;

5.將操作該磁碟file的磁碟操作函式儲存在vm_ops中

注意:這裡沒有對應 的頁目錄表項建立頁表,更不存在設定頁表項了。

假設現在程式中有一條指令需要讀取上面vm_start--vm_end之間的某內容

例如:mov [0x08000011],%eax,那麼將會執行如下序列:

1.cpu依據cr3(current->pgd)找到0x08000011位址對應的pgd[i],由於該pgd[i]內容保持為初始化狀態即為0,導致cpu異常.

2.do_page_fault被呼叫,在該函式中,為pgd[i]在記憶體中分配乙個頁表,並讓該表項指向它,如下圖所示:

注意:這裡i為0x08000011高10位,j為其中間10位,此時pt表項全部為0(pte[j]也為0);

3.為pte[j]分配乙個真正的物理記憶體頁面,依據vm_area_struct中的vm_file、vm_pgoff和vm_ops,呼叫filemap_nopage將磁碟file中vm_pgoff偏移處的內容讀入到該物理頁面中,如下圖所示:

①。分配物理記憶體頁面;

②。從磁碟檔案中將內容讀取到物理記憶體頁面中

從上面我們可以知道,在程序建立的過程中,程式內容被對映到程序的虛擬記憶體空間,為了讓乙個很大的程式在有限的物理記憶體空間執行,我們可以把這個程式的開始部分先載入到物理記憶體空間執行,因為作業系統處理的是程序的虛擬位址,如果在進行虛擬到實體地址的轉換工程中,發現實體地址不存在時,這個時候就會發生缺頁異常(nopage),接著作業系統就會把磁碟上還沒有載入到記憶體中的資料載入到物理記憶體中,對應的程序頁表進行更新。也許你會問,如果此時物理記憶體滿了,作業系統將如何處理?

下面我們看看linux作業系統是如何處理的:

如果乙個程序想將乙個虛擬頁裝入物理記憶體,而又沒有可使用的空閒物理頁,作業系統就必須淘汰物理記憶體中的其他頁來為此頁騰出空間。

在linux作業系統中,物理頁的描敘如下:

struct mem_map

如果從物理記憶體中被淘汰的頁來自於乙個映像或資料檔案,並且還沒有被寫過,則該頁不必儲存,它可以丟掉。如果有程序在需要該頁時就可以把它從映像或資料檔案中取回記憶體。

然而,如果該頁被修改過,作業系統必須保留該頁的內容以便晚些時候在被訪問。這種頁稱為"髒(dirty)頁",當它被從記憶體中刪除時,將被儲存在乙個稱為交換檔案的特殊檔案中。

相對於處理器和物理記憶體的速度,訪問交換檔案要很長時間,作業系統必須在將頁寫到磁碟以及再次使用時取回記憶體的問題上花費心機。

如果用來決定哪一頁被淘汰或交換的演算法不夠高效的話,就可能出現稱為"抖動"的情況。在這種情況下,頁面總是被寫到磁碟又讀回來,作業系統忙於此而不能進行真正的工作。

linux使用"最近最少使用(least recently used ,lru)"頁面排程技巧來公平地選擇哪個頁可以從系統中刪除。這種設計系統中每個頁都有乙個"年齡",年齡隨頁面被訪問而改變。頁面被訪問越多它越年輕;被訪問越少越老。年老的頁是用於交換的最佳候選頁。

程序位址空間與虛擬儲存空間

linux中的每個程序都有自己的虛擬位址空間。作業系統的乙個最重要的基本管理目的就是避免程序之間的相互影響。下面將介紹虛擬位址空間。通過虛擬位址訪問記憶體有以下優勢 某台計算機總的記憶體大小是 128m 現在同時執行兩個程式 a 和 b a 需占用記憶體 10m b 需占用記憶體 110 計算機在給...

Linux程序位址空間與虛擬記憶體

32位機器上linux 作業系統中的程序的位址空間大小是4g,其中0 3g是使用者空間,3g 4g是核心空間。程序的位址空間存在於虛擬記憶體中。虛擬記憶體不能被禁用。程序位址空間 程序位址空間分為核心空間和使用者空間 因為每個程序可以通過系統呼叫進入核心,因此,linux核心由系統內的所有程序共享。...

程序位址空間與虛擬儲存空間的理解

在進入正題前先來談談作業系統記憶體管理機制的發展歷程,了解這些有利於我們更好的理解目前作業系統的記憶體管理機制。一 早期的記憶體分配機制 在 早期的計算機中,要執行乙個程式,會把這些程式全都裝入記憶體,程式都是直接執行在記憶體上的,也就是說程式中訪問的記憶體位址都是實際的物理記憶體位址。當計算機同時...