linux之旅 關於虛擬記憶體

2022-05-08 17:21:10 字數 3353 閱讀 5005

虛擬記憶體是個怎麼強調也不過分的概念,它的存在極大地方便了程式設計任務,解放了程式設計師的手腳。下面看看虛擬記憶體的作用以及如何在儲存管理機制的基礎上實現它。

我們知道程式**和資料必須駐留在記憶體中才能得以執行,然而系統記憶體數量很有限,往往不能容納乙個完整程式的所有**和資料,更何況在多工系統中,可能需要同時開啟子處理程式,畫圖程式,瀏覽器等很多任務,想讓記憶體駐留所有這些程式顯然不太可能。因此首先能想到的就是將程式分割成小份,只讓當前系統執行它所有需要的那部分留在記憶體,其它部分都留在硬碟。當系統處理完當前任務片段後,再從外存中調入下乙個待執行的任務片段。的確,老式系統就是這樣處理大任務的,而且這個工作是由程式設計師自行完成。但是隨著程式語言越來越高階,程式設計師對系統體系的依賴程度降低了,很少有程式設計師能非常清楚的駕馭系統體系,因此放手讓程式設計師負責將程式片段化和按需調入輕則降低效率,重則使得機器崩潰;再乙個原因是隨著程式越來越豐富,程式的行為幾乎無法準確**,程式設計師自己都很難判斷下一步需要載入哪段程式。因此很難再靠預見性來靜態分配固定大小的記憶體,然後再機械地輪換程式片進入記憶體執行。系統必須採取一種能按需分配而不需要程式設計師干預的新技術。

虛擬記憶體(之所以稱為虛擬記憶體,是和系統中的邏輯記憶體和物理記憶體相對而言的,邏輯記憶體是站在程序角度看到的記憶體,因此是程式設計師關心的內容。而物理記憶體是站在處理器角度看到的記憶體,由作業系統負責管理。虛擬記憶體可以說是對映到這兩種

不同視角記憶體的乙個技術手段。)技術就是一種由作業系統接管的按需動態記憶體分配的方法,它允許程式不知不覺中使用大於實際物理空間大小的儲存空間(其實是將程式需要的儲存空間以頁的形式分散儲存在物理記憶體和磁碟上),所以說虛擬記憶體徹底解放了程式設計師,從此程式設計師不用過分關心程式的大小和載入,可以自由編寫程式了,繁瑣的事情都交給作業系統去做吧。

虛擬記憶體是將系統硬碟空間和系統實際記憶體聯合在一起供程序使用,

給程序提供了乙個

比記憶體大得多的虛擬空間。在程式執行時,只要把虛擬位址空間的一小部分對映到記憶體,其餘都儲存在硬碟上

(也就是說程式虛擬空間就等於實際物理記憶體加部分硬碟空間)

。當被訪問的虛擬

位址不在記憶體時,則說明該位址未被對映到記憶體,而是被存貯在硬碟中,因此需要的虛擬儲存位址

隨即被調入到記憶體

;同時當系統記憶體緊張時,也可以把

當前不用的虛擬儲存空間換出到硬碟

,來騰出物理記憶體空間

。系統如此週而復

始地運轉

——換入、換出

,而使用者幾乎無法查覺

,這都是拜虛擬記憶體機制所賜

linux的swap分割槽就是硬碟專門為虛擬儲存空間預留的空間。經驗大小應該是記憶體的兩倍左右。有興趣的話可以使用swapon -s 檢視交換分割槽大小。

大道理很好理解,無非是用記憶體和硬碟空間合成為虛擬記憶體空間。但是這一過程中反覆執行的位址對映(虛擬位址對映到實體地址)和虛擬位址換入換出卻值得仔細推敲。系統到底是怎麼樣把虛擬位址對映到實體地址上的呢?記憶體又如何能不斷地和硬碟之間換入換出虛擬位址呢?

利用段機制能否回答上述問題呢?邏輯位址通過段機制後變為乙個32位的位址,足以覆蓋4g的記憶體空間,當程式需要的虛擬位址不在記憶體時,只依靠段機制很難進行虛擬空間地換入換出,因為不大方便把整段大小的虛擬空間在記憶體和硬碟之間調來調去(老式系統中,會笨拙地換出整段記憶體甚至整個程序,想想這樣做會有那些惡果吧!)。所以很有必要尋找乙個更小更靈活的儲存表示單位,這樣才方便虛擬位址在硬碟和記憶體之間調入調出。這個更小的儲存管理單位便是頁(4k大小)。管理頁換入換出的機制被稱為頁機制

。使用頁機制,4g空間被分成2的20次方個4k大小的頁面(頁面也可定為4m大小),因此定位頁面需要的索引表(頁表)中每個索引項至少需要20位,但是在頁表項中往往還需要附加一些頁屬性,所以頁表項實際為32位,其中12位用來存放諸如「頁是否存在於記憶體」或「頁的許可權」等資訊。

前面我們提到了線性位址是32位。它其中高20位是對頁表的索引,低12位則給出了頁面中的偏移。線性位址經過頁表找到頁面基位址後和低12位偏移量相加就形成了最終需要的實體地址了。

在實際使用中,並非所有頁表項都是被存放在乙個大頁表裡,因為每個頁表項佔4個位元組,如果要在乙個表中存放2的20次方個頁表項,就需要4m的連續儲存空間。這麼大的連續空間可不好找,因此往往會把頁表分級儲存,比如分兩級,那麼每級頁表只需要4k連續空間了。

兩級頁表搜尋如同看章回**,先找到在哪一章裡,然後在找在該章下的哪一節。具體過程看看下圖:

綜上所述,位址轉換工作需要兩種技術,一是段機制,二是頁機制。段機制處理邏輯位址向線性位址的對映;頁機制則負責把線性位址對映為實體地址。兩級對映共同完成了從程式設計師看到的邏輯位址轉換到處理器看到的實體地址這一艱鉅任務。

你可以將這兩種機制分別比作乙個位址轉換函式,段機制的變數是邏輯位址,函式值是線性位址;頁機制的變數是線性位址,函式值是實體地址。位址轉換過程如下所示。

邏輯位址

——(段函式)

——>

線性位址

——(頁函式)

——>

實體地址。

雖然段機制和頁機制都參與對映,但它們分工不同,而且相互獨立互不干擾,彼此之間不必知道對方是否存在。

下面我們結合linux例項簡要地看看段頁機制如何使用。

段機制在linux裡用得有限,並沒有被完全利用。每個任務並未分別安排各自獨立的資料段,**段,而是僅僅最低限度的利用段機制來隔離使用者資料和系統資料——linux只安排了四個範圍一樣的段,核心資料段,核心**段,使用者資料段,使用者**段,它們都覆蓋0-4g的空間,所不同的是各段屬性不同,核心段特權級為0,使用者段特權級為3。這樣分段,避免了邏輯位址到線性位址的轉換步驟(邏輯位址就等於線性位址),但仍然保留了段的等級這層最基本保護。

每個使用者程序都可以看到4g大小的線性空間,其中0-3g是使用者空間,使用者態程序可以直接訪問;從3g-4g空間為核心空間,存放核心**和資料,只有核心態程序能夠直接訪問,使用者態程序不能直接訪問,只能通過系統呼叫和中斷進入核心空間,而這時就要進行的特權切換。

說到特權切換,就離不開任務門,陷阱門/中斷門等概念。陷阱門和中斷門是在發生陷阱和中斷時,進入核心空間的通道。呼叫門是使用者空間程式相互訪問時所需要的通道,任務門比較特殊,它不含任何位址,而是服務於任務切換(但linux任務切換時並未真正採用它,它太麻煩了)。

對於各種門系統都會有對應的門描述符,和段描述符結構類似,門描述符也是由對應的門選擇字索引,並且最終會產生乙個指向特定段內偏移位址的指標。這個指標指向的就是將要進入的入口。利用門的目的就是保證入口可控,不至於進入到核心中不該訪問的位置。

看看linux中如何使用分頁。

linux中每個程序都會有各自不同的頁表,也就是說程序的對映函式互不相同,保證每個程序虛擬位址不會對映到相同的實體地址上。這是因為程序之間必須相互獨立,各自的資料必須隔離,防止資訊洩漏。

那麼在使用者程序需要訪問核心空間時如何做呢?

Linux虛擬記憶體

linux採用虛擬段頁式儲存方式來管理記憶體,程式的基本邏輯儲存單元,也可以說是程式段。linux中有四個段,段,資料段,bss段,堆疊段。虛擬位址從低到高依次是 段,資料段,bss段,堆疊段。其中 段為程式本身 二進位制指令 資料段為 中初始化了的全域性變數和靜態變數,bss段為為初始化的全域性變...

Linux虛擬記憶體

一 虛擬記憶體 1 系統會為每個程序分4g的虛擬記憶體空間。32個0 32個1 位址範圍。2 使用者只能使用虛擬位址,無法直接使用物理記憶體。3 虛擬位址與物理記憶體進行對映才能使用,否則就會產生段錯誤。4 虛擬位址與物理記憶體的對映由作業系統動態維護。5 讓使用者使用虛擬位址一方面為了安全,另一方...

linux記憶體與虛擬記憶體

linux支援虛擬記憶體 記憶體 記憶體條 物理記憶體 實際存在 程式中的記憶體 虛擬記憶體 os對映出來的 直接對映 檔案對映 提速 檔案io操作 耗時長 記憶體操作 耗時短 mmap函式可以把檔案對映成虛擬記憶體,像操作記憶體一樣去操作檔案。mmap函式可以直接對映一塊虛擬記憶體。include...