Linux內存的分頁管理詳解||物理內存||虛擬內存||聯繫||分頁機制||工作原理

目錄

 

1.內存

2.虛擬內存

3.內存的分頁管理

1.虛擬內存地址到物理內存地址的尋址

2.磁盤地址(虛擬內存空間)到物理內存地址的映射

3.虛擬內存是如何工作的


1.內存

內存是計算機的主存儲器,它爲進程開闢出進程空間,讓進程在其中保存數據。它的最小的存儲單位一般是字節。內存會爲每各字節進行編號,從0開始依次遞增(線性的)。通常我們會用16進制來表示內存的地址。同時,內存地址的編號範圍和地址總線的個數是直接相關的,例如地址總線的個數爲32,那麼內存的地址編號範圍爲0x00000000到0xFFFFFFFF(爲2的32次方)。

當代操作系統既要求能夠使多個程序共享系統資源,同時還要求內存限制對程序開發者透明,在此需求下,虛擬內存應運而生。

2.虛擬內存

虛擬內存實際上是在磁盤上劃分一塊進程專屬的空間去充當內存。虛擬內存(邏輯地址)支持程序訪問比系統物理可用內存大的多的內存空間,而且也使得多個程序共享內存變量變得高效。虛擬內存依靠透明的使用磁盤空間,得以使程序運行起來好像它們使用比系統物理內存更多的內存空間。磁盤相比於物理內存更加低廉,而且容量巨大,因此可以作爲物理內存的擴充。之所以稱虛擬內存,就是因爲磁盤存儲體可以有效的充當內存,但它並不是內存。

下圖描述了多級數據存儲體的層次關係:

運行中的每個進程都有自己的一套虛擬內存空間,空間的大小一般與地址總線的個數有關,32爲操作系統的虛擬內存大小爲2的32次方(4G)。同時,虛擬內存的編號方法與物理內存類似。從功能上說,虛擬內存地址和物理內存地址的功能是相同的,都是爲數據提供位置索引。由於每個進程都有一份獨立的虛擬內存空間,所以不同進程中虛擬地址相同的地址表示數據很可能不一樣,如下圖所示:(圖中的進程空間相當於磁盤上的某一塊空間)

因此,進程對物理內存是一無所知的,因爲虛擬內存的存在將進程與物理內存隔離開來,只能通過MMU(內存管理單元)將虛擬內存地址轉換成物理內存地址,間接的去訪問物理內存。從本質上說,虛擬內存的存在,剝奪了進程直接訪問物理內存的權力,但是嗎,正是因爲如此,才保證進程之間的相互獨立性,減少了進程出錯的可能性。

另一方面,有了虛擬內存地址,內存共享也變得簡單。操作系統可以把同一物理內存區域對應到多個進程空間。這樣,不需要任何的數據複製,多個進程就可以看到相同的數據。內核和共享庫的映射,就是通過這種方式進行的。每個進程空間中,最初一部分的虛擬內存地址,都對應到物理內存中預留給內核的空間。這樣,所有的進程就可以共享同一套內核數據。共享庫的情況也是類似。對於任何一個共享庫,計算機只需要往物理內存中加載一次,就可以通過操縱對應關係,來讓多個進程共同使用。

使用虛擬內存的優點:

可以彌補物理內存大小的缺陷,使每個進程都有自己的獨立空間,同時使數據共享成爲可能。

缺點:

使用虛擬內存會佔用一定的磁盤空間,加大了對磁盤的讀寫。

3.內存的分頁管理

使用虛擬內存的時候,我們需要建立虛擬地址與物理地址的對應關係,如果我們繼續使用存儲的最小單位(字節)充當存儲的基本單元,那麼就需要爲每個字節都去建立一個對應關係,這樣會消耗巨大的計算機存儲資源。因此操作系統採用分頁的機制來建立這種對應關係,所謂分頁,就是以更大的尺寸去充當存儲的基本單元,在Linux系統中一個頁的大小通常是4KB=4096字節。

linux分頁管理即是:

將虛擬地址空間以4KB的大小,分成若干個,對頁進行編號(從0開始),並從0開始在頁內進行編號。首先看如下32位尋址空間的虛擬地址結構圖:

上述數字均爲16進制,前12位表示頁內偏移地址,後20位表示頁號,因此在進程的虛擬地址空間中,頁的大小和頁的數目分別如下:

2^12 = 4KB

2^20 = 1M

因此32位系統的尋址能力位:1M x4KB = 4G.

同時,物理內存也會按照同樣的大小(4KB),分成框或塊,也是對塊進行編號,同時塊內進行編號。

同時操作系統還會通過維護一張表(頁表),記錄了每一頁和框的對應關係。如下圖:(圖中是簡單的單級頁表,linux中採用了多級頁表,道理一樣,都是逐層建立對應關係)

頁-頁表-框

由於各個進程的各個頁離散的存儲在內粗內得不同物理塊上,頁表的存在,使得進程能在內存中找到每個頁面所對應的物理塊,保證了進程的正確運行。

內存的分頁,可以極大地減少所要記錄的內存的對應關係。由於每頁的大小式4096個字節,因此內存中的總頁數只是總字節數的4096分之一。對應關係也縮減爲以字節爲基本存儲單元的4096分之一。分頁讓虛擬內存地址的設計有了實現的可能。

1.虛擬內存地址到物理內存地址的尋址

對於某特定機器,其地址結構式一定的。若給定一個邏輯地址空間中的地址A,頁面大小L,則頁號P和頁內地址可通過下面方式求得:

P = int[A/L]   []表示向下取整。

d = A %L

根據頁表和頁號P可以找到物的理內存中對應塊,數據的地址就位於塊內的地址d處。

2.磁盤地址(虛擬內存空間)到物理內存地址的映射

由於程序的數據一般先存儲與磁盤中(不是內存),當我們使用虛擬內存的時候,磁盤中的數據也被分割成以頁爲單位的基本單元,頁可以在磁盤與內存之間來回移動。這樣,程序正在使用的那部分數據所屬的頁就可以從磁盤中至於內存中,以便進行快速的訪問,而未使用的部分則被臨時存儲在磁盤中,如此可以減輕待訪問數據存放在磁盤中而導致讀取時間過長的問題。當進程訪問一個地址時,該地址所在的頁被載入內存,對頁中任意一數據的請求都會變成對該頁的訪問。如果頁中的任一地址以前都沒有訪問過,說明該頁並沒有裝入內存(因爲只有進程需要,纔會將對應頁裝入內存,所以裝入內存中的頁一定是訪問過的)。對頁中地址的第一次訪問便會產生一個失敗或缺頁(因爲第一次訪問的時候,所訪問的頁肯定不在內存中),因此必須從磁盤中進行請求。當發生缺頁的時候,內核必須選擇一個頁面,然後將其內容寫回到磁盤,從而用程序剛剛請求的頁的內容來填充它。頁面的選擇通過缺頁置換算法來確定。

3.虛擬內存是如何工作的

當每個進程創建的時候,內核會爲進程分配4G的虛擬內存,當進程還沒有開始運行時,這只是一個內存佈局。實際上並不立即就把虛擬內存對應位置的程序數據和代碼(比如.text .data段)拷貝到物理內存中,只是建立好虛擬內存和磁盤文件之間的映射就好(叫做存儲器映射)。這個時候數據和代碼還是在磁盤上的。當運行到對應的程序時,進程去尋找頁表,發現頁表中地址沒有存放在物理內存上,而是在磁盤上,於是發生缺頁異常,於是將磁盤上的數據拷貝到物理內存中。

另外在進程運行過程中,要通過malloc來動態分配內存時,也只是分配了虛擬內存,即爲這塊虛擬內存對應的頁表項做相應設置,當進程真正訪問到此數據時,才引發缺頁異常。

可以認爲虛擬空間都被映射到了磁盤空間中(事實上也是按需要映射到磁盤空間上,通過mmap,mmap是用來建立虛擬空間和磁盤空間的映射關係的)
 

 

參考文章:

https://www.cnblogs.com/vamei/p/9329278.html

https://www.cnblogs.com/leohahah/p/6921731.html

https://baike.baidu.com/item/基本分頁存儲管理方式/7866872?fr=aladdin

https://blog.csdn.net/u014338577/article/details/82750771

《unix內核編程》

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章