天天看點

有關虛拟記憶體

real,virtual,transparent的差別

如果它存在,而且你能看到它,那麼它是真實的(real);

如果它不存在,但你能看見它,那麼它是虛拟的(virtual);

如果它存在,但是你看不見它,那麼它是透明的(transparent)。

對應到記憶體,我們可以知道,實體記憶體是透明的,我們在編寫程式時感覺不到它的存在;而程式真正感覺到的,也就是指針、堆棧、資料區、代碼區所存在的,是虛拟記憶體,也就是virtual memory。

作業系統應該給上層的應用程式以充分發揮的空間,是以,不應該盲目的限制配置設定給一個程序多大的位址空間。而記憶體資源畢竟是有限的,現代作業系統對多任務的處理又是一個标配,那應該如何辦呢?在這種情況下,虛拟記憶體出現了,它的基本思路是用廉價但緩慢的磁盤來擴充快速卻昂貴的記憶體(存儲器山永遠是存在的,無論技術如何發展)。在任一時刻,實體記憶體僅儲存實際需要的資料,不需要的,作業系統會負責将其轉入硬碟(廣義的)之中,這一切是對程式員透明的。

多層存儲與之類似,除了硬碟和記憶體外,還要考慮CPU寄存器,L1、L2緩存,以及廣義的網絡裝置。

按照 寄存器,L1、L2緩存,記憶體,硬碟,網絡裝置的順序,通路速度逐漸降低,機關bit的成本逐漸升高。這樣一種金字塔型的體系結構,通過犧牲一些通路速度來大幅降低存儲系統的實作成本。而如果應用程式以及作業系統設計的足夠緩存友好(cache-friendly)的話,對程式的運作速度影響不大。這就會引出如何設計實作cache-friendly程式的問題,這個以後再講。

作業系統負責虛拟記憶體的具體實作細節。在作業系統的協助下,每個程序都以為自己擁有整個位址空間的獨家通路權。而這個幻覺就是通過“虛拟記憶體”實作的。記憶體管理硬體(MMU注意,速度要求,這是有硬體實作的,需要晶片的支援)負責把虛拟位址翻譯成實體位址,并讓一個程序始終運作于系統的真正記憶體中。應用程式程式員隻看到虛拟位址,并不知道自己的程序在磁盤和記憶體之間來回切換。

虛拟記憶體通過頁(page)的形式來組織。在磁盤上,有一個特殊的“交換區”,用于儲存從記憶體中換出的程序。在我們普通的pc上,交換區的大小一般是實體記憶體的幾倍。在windows上可以通過“我的電腦”->進階->性能->設定來自行設定,而linux則多為安裝時設定swap分區大小(我自己曾因為swap分區設定和記憶體一樣導緻無法待機)。隻用使用者程序被換出,而系統程序是常駐與記憶體的,當然也包括負責使用者程序排程的系統程序。而這些,對應用程式程式員以及最終的作業系統使用者都是透明的。

程序隻能操作位于實體記憶體中的頁面。當程序引用不在實體記憶體中的頁面時,MMU通過産生一個頁錯誤通知核心進行響應。核心判斷這個響應,判斷該引用是否有效。如果無效向上彙報(産生segmentation violation信号),如果有效,則從磁盤取出該頁進入記憶體,繼續程式的執行。

用下面這個簡單的程式,我們可以判斷一個程序可以配置設定多大的記憶體:

#include<cstdio>

#include<cstdlib>

using namespace std;

int main()

{

int MB = 0;

while(malloc(1<<20)) MB++;

printf("Allocated %d MB total/n",MB);

//system("pause");

}

在我windows 本地機器上,可以看到得到的結果是857MB(不同次運作會有差别),在linux機器上得到的結果是3056MB,而win的虛拟記憶體設定是1024MB,可以發現這個結果略小于虛拟記憶體的大小,也就是說,一個程序可以配置設定的記憶體大小是和虛拟記憶體大小直接相關(保證虛拟記憶體始終可以把這個程式的“全部”都裝進去),而和實體記憶體實際大小關系不大。

繼續閱讀