進程的虛擬內存

進程的虛擬內存

進程屬性信息的task_struct結構體,其中包含進程使用的內存信息。在32位的操作系統中,當進程創建的時候(程序運行時),系統會爲每一個進程分配大小爲4GB的虛擬內存空間,用於存儲進程屬性信息。

C語言中的變量,通常使用&運算符來獲得其地址,那麼,這個地址就是虛擬地址,在簡單的單片機中,編寫的代碼編譯時都需要指定物理RAM空間分佈,不會有虛擬地址的概念,地址就是指在RAM中的實際物理地址

爲什麼需要虛擬空間機制

首先程序代碼和數據必須駐留在內存中才能得以運行,然而系統內存大小是有限的,有時可能不能容納一個完整的程序的所有代碼和數據,更何況在多任務系統中,可能同時要打開子處理程序、瀏覽器等多種任務,想讓內存駐留所有的這些程序顯然不太可能。因此,首先能想到的是將程序分割成小份,只讓當前系統運行它的所有需要的那部分留在內存,其他部分都留在硬盤。當系統處理完當前任務片段後,再從外存中調入下一個待運行的任務片段。老式系統就是這樣處理大任務的,而且這個工作是由開發者自行完成。然而隨着程序越來越豐富,由於程序的行爲幾乎準確預測,因此很難再靠預見性來靜態分配固定大小的內存,然後再機械地輪換程序片進入內存執行。系統必須採用一種能按需分配的新技術

這種按需分配的技術就是虛擬內存機制。之所以稱之爲虛擬內存,說明內存只是邏輯上存在的,並非真實的物理內存,而且進程的分配的虛擬內存空間可能比實際使用物理內存要大很多。程序最終的執行,也是由CPU操作物理內存完成的。因此,虛擬內存需要與實際的物理內存建立起一定的聯繫,從而對於進程來說,保證訪問的虛擬內存空間是有意義的,而不是訪問了一個假設的地址值

物理內存與虛擬內存建立聯繫通過地址映射得來。所謂映射,就是一個地址轉換的過程,通俗地講,就是讓虛擬地址與物理地址建立一一對應的關係。一旦這種關係建立,進程只需操作虛擬地址即可,然後通過查找這一虛擬地址與實際地址建立的關係,即可實現對實際地址的使用。當進程退出不需要內存資源釋放時,將這一對應關係斷開即可,此時虛擬地址就毫無意義,因爲它沒有和任何物理地址有關係

系統雖然爲每一個進程分配了4GB的虛擬內存空間,但實際情況是進程按照當前運行對內存的需求,通過與實際的物理內存建立映射關係,獲取分配的內存資源。在這一過程中,所需的地址在其生命週期中可以發生變化。同時,虛擬內存使得進程認爲它的擁有連續可用的內存(一段連續完整的內存);但實際上,它通常是映射的多個不連續的物理內存分段來的

虛擬內存管理:如何實現虛擬地址與實際地址的映射

物理地址與虛擬地址建立關係,進程通過操作虛擬地址,而得到與之建立關係的實際物理地址的使用。這種地址關係建立,是通過頁映射表現的

虛擬內存的規劃之一是將每個程序使用的內存切割成小型的、固定大小的“頁”單位(一般頁面的大小爲4096字節=4kb)。相應地,將RAM劃分成一系列與虛擬頁尺寸相同的頁幀。內核需要爲每一個進程維護一張頁映射表。該頁映射表中的每個條目指出一個虛擬“頁”在RAM中的所在位置,在進程虛擬地址空間中,並非所有的地址範圍都需要頁表條目。由於可能存在大段的虛擬地址空間並未投入使用,故而也沒有必要爲其維護相應的頁表條目

虛擬內存管理使進程的虛擬地址空間與RAM物理地址空間隔離開來,有優點如下

  1. 進程與進程、進程與內核相互隔離,一個進程不能讀取或修改另一個進程或內核的內存,這是因爲每個進程的頁表條目指向RAM中的截然不同的物理頁面集合
  2. 適當情況下,兩個或者多個進程能夠共享內存。這是因爲內核可以使不同進程的頁表條目指向相同的RAM頁
  3. 便於實現內存保護機制:也就是說,可以對頁表條目進行標記,以表示相關頁面的內容是可讀、可寫、可執行抑或是這些保護措施的組合。多個進程共享RAM頁時,允許每個進程對內存採取不同的保護措施。例如,一個進程可能以只讀方式訪問某RAM頁,而另一個進程則以讀寫方式訪問該頁
  4. 程序員和編譯器、鏈接器之類的工具無須關注程序在RAM中的物理佈局
  5. 因爲需要駐留在內存中的僅是程序的一部分,所以程序的加載和運行都很快。而且,一個進程所佔用的虛擬內存大小能夠超出RAM容量

進程的內存佈局

Linux操作系統採用的虛擬內存管理技術,該虛擬內存空間大小爲4GB的線性虛擬空間,進程只管自己的訪問虛擬地址,無須知道物理地址的映射情況。利用這種虛擬地址不但更安全(用戶不能直接訪問物理內存),而且用戶程序可以使用比實際物理內存更大的地址空間

4GB的進程地址空間會被分成兩個部分--用戶空間與內核空間。用戶地址空間是03GB(0XC00000000),內核地址空間佔據34GB。通常情況下,用戶只能訪問用戶的虛擬地址,不能訪問內核空間虛擬地址。只有用戶進程使用系統調用(代表用戶進程在內核態執行)時纔可以訪問內核空間。當進程切換時,用戶空間就會跟發生變化;而內核空間是由內核負責映射的,是固定的,它並不會隨着進程改變。內核空間地址有自己對應的頁表,用戶進程各自由不同的表,每個進程的用戶空間都是完全獨立、互不相干

用戶空間包括以下幾個功能區域

  1. 程序代碼段:源代碼,具有隻讀屬性,包含程序代碼(.init和.text)和只讀數據(.rodata)
  2. 數據段:存放的是全局變量和靜態變量。其中初始化數據段(.data)【靜態數據區】存放顯示初始化的全局(Global)變量和靜態(Static)變量;未初始化數據段,此段通常也被稱爲BSS段(.bss),存放未進行顯示初始化的全局變量和靜態變量
  3. 棧:系統管理,由系統自動分配釋放,存放函數的參數值、局部變量的值、返回地址等
  4. 堆:用戶管理,存放動態分配的數據,一般由程序動態分配和釋放,若程序不釋放,程序結束時可能由操作系統回收。例如:使用malloc()函數申請空間
  5. 共享庫的內存映射區域:這是Linux動態鏈接器和其他共享庫代碼的映射區域
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章