作業系統記憶體管理-原理

WEB發表於2014-03-24

          任何新技術都是在一點一點的積累中成熟並呈現在世人的面前,就像猿人程式成人也不是一簇而就的,而是在漫長的歲月中一點一點的進化與完善。還比如現代的吸塵器,當前發明吸塵器的那個人只是用了一臺風扇的電機和葉片以及一個布口袋製成的,後來也是一點一點的改善成為現在的使用方便的吸塵器。

          作業系統的記憶體管理也是同樣的道理,起初的作業系統並沒有現代作業系統的虛擬記憶體管理機制,而是指令直接訪問實體記憶體,並且在記憶體中同一時間只能執行一個程式,因為如果是多個程式,程式A中的指令有可能會修改程式B的記憶體地址,造成程式B崩潰或錯誤的計算結果。

        後來開始支援多工也就是同時可以執行多個程式,為每個程式都分配一塊獨立的記憶體地址並寫有保護位,其它程式指令是無法訪問當前程式的地址空間的,並且利用上了cpu的基址暫存器和界限暫存器來表達當前程式的實體地址訪問開始端和範圍,開始支援程式指令以相對記憶體地址執行。支援多工固然是好,讓cpu的利用率大大提高,提高了工作效率,同時讓程式以相對地址訪問更加解放了程式設計師的工作。可是多程式帶來的問題就是記憶體空間大小的侷限性,就算有1G記憶體空間,如果我的程式加上正文加上資料算100M,也就最多能執行10個,這還不算作業系統佔用的,所以人們後來就發明了交換技術,當記憶體無法同時容納多個程式是,就根據策略比如很久以後才會執行的程式,就將程式的正文還有堆疊以及程式計數器這些程式映像儲存到硬碟上,當執行時再次裝入記憶體,恢復暫存器和程式計數器,這樣雖然解決了記憶體空間有限的問題,但是也帶來了新的問題,程式資料在記憶體與硬碟上的往復交換帶來了大量的io讀寫磁碟操作,大大降低了程式的執行效率。

        經過以上的兩個階段的問題與整理,人們終於走上了虛擬記憶體的道路,現代的大多作業系統記憶體管理都採用分頁和分段的記憶體管理機制,所以下面我們詳細的說一下機制。

       所謂虛擬記憶體,簡單的來說就是程式指令訪問的記憶體地址不是真的記憶體的實體地址,而是需要一個轉換過程才能訪問到實體地址,讀取或存取資料。

       在作業系統中讓執行的每個程式擁有自己的空間地址,這個地址被分成多個塊,每個塊被稱為一頁或“頁面”,每一頁有連續的虛擬記憶體地址,每一個頁都對應實體記憶體中的一塊,這種塊被稱為“頁框”,頁框和頁面同等大小,頁面與頁框的對應關係被稱為頁表儲存在程式的地址空間中。當指令訪問一個記憶體地址是,經過硬體(cpu中的mmu,負責虛擬地址轉換,每一個程式執行時,就會將頁表資訊設定mmu,讓mmu知道頁面與頁框的關係,從而快速計算出實際實體地址)快速計算出實際的實體地址,讀取地址獲取資料,如果發現訪問的虛擬地址不存在,則有作業系統負責將缺失的頁面由磁碟裝如記憶體,並更新頁表中頁面與頁框的對應關係。

       頁表中儲存著頁面與頁框的對映關係,當cpu發出一條訪問記憶體的指令,mmu會根據記憶體地址的前幾位在頁表中找出對應的頁面與頁框的記錄,從而知道了頁框的地址,採用地址的後幾位作為實體地址區間頁框的偏移量,這樣找到了頁框並且知道了該頁框上的位置,就知道了訪問的真實的記憶體地址。

      頁表中還儲存了一些保護位。第一個是狀態位,就是頁面是否在記憶體中,如果存在則根據頁框與頁面的對應關係找出實體地址,如果不存在,則引起缺頁中斷有作業系統將缺失頁面裝入記憶體並更新頁表。第二則是保護位,記錄只讀或可讀寫,第三是記錄頁面修改情況,以便在將頁框中的資訊置換到硬碟時寫入磁碟還是直接丟棄。第四個是禁止快取記憶體位,如果作業系統一直在讀取軟盤上的資料,保證cpu讀取到的資料只是最新的是很有必要的,所以要設定這個位。

     當頁框也就是實體記憶體不夠使用的時候,作業系統會根據一些頁面置換演算法將記憶體中的資料置換到磁碟上的交換空間(swap),騰出空閒的頁框來儲存需要在記憶體中執行的程式和相關資料。

     在所有的頁面置換演算法中,以老化演算法應用最廣泛和最實用,下面大概說一下這個頁面置換演算法。

     在cpu剛使用的頁面很可能在後面的幾條指令中被使用,反過來說,已經很久沒有使用的頁面在未來的一段時間很可能仍然不被使用,因為程式指令是順序執行的,當然存在在jmp這樣的跳轉,可是大多數情況,程式指令還是以此來執行的。老化演算法就是根據這個思想來實現的,在發生缺頁中斷時,置換很久沒有使用的頁面,這個策略被稱為LRU。

    老化演算法的大概實現思路是,在記憶體中儲存一個資料結構,裡面儲存頁面的使用次數,每次時鐘滴答後,將記憶體中頁面的引用次數加到資料結構裡面的數值上,每次先將數值右移一位(1000=>0100)然後將本次使用設定到數值的最左邊((使用)1100 不使用0100),然後在發生頁面替換時,則替換數值最小的那個也就是使用次數最小的.

    下面說一下作業系統中發生缺頁中斷時的處理流程

    1.當前程式的某條指令被放入cpu,cpu發出指令訪問記憶體,該地址不存在,系統則陷入核心。

    2.核心首先儲存當前程式的堆疊暫存器以及程式計數器來儲存當前程式的進度印象,為處理完缺頁中斷後繼續執行當前程式做準備。

    3.作業系統根據cpu中暫存器發現發生缺頁中斷的記憶體地址。如果暫存器中沒有,則必須檢索上一部儲存的程式計數器來發現發生缺頁中斷的虛擬記憶體地址

    4.發現了需要處理的地址後,系統檢查這個地址是否有效,是否越界。如果不符合檢查條件,則殺掉該程式,繼續執行別的程式。當符合條件。則系統檢查是否有空閒頁框,如果不存在空閒頁框,則呼叫頁面置換演算法尋找一個頁面調換出去,為此頁面騰出一個頁框。

    5.發現需要置換的頁面後,則檢查該頁面是否屬於髒頁面也就是資料裝入記憶體後被修改過,則需要呼叫程式將此資料寫回磁碟,併發生一次上下文切換,掛起當前處理缺頁中斷的程式,讓其他程式繼續執行。

    6.當頁面乾淨後,則呼叫io程式將資料從磁碟寫入記憶體,並掛起當前程式,讓系統繼續排程其他待執行程式。

    7.資料裝入頁框後,掛起程式被喚醒。系統將程式計數器以及各個暫存器以及堆疊恢復到cpu和產生缺頁中斷的程式空間地址中,繼續執行產生缺頁中斷的程式。

     在作業系統中,一個程式包含資料,程式正文,還有堆疊,這些資料都放在一個程式地址空間中,堆疊會隨著程式的執行變大和變小,資料也會跟著程式的進度而變化,當將這些不同型別的資料都放在一起時管理起來是很複雜的,比如堆疊的變大需要更多的記憶體空間時,是發生缺頁中斷還是增加程式地址的記憶體空間。其實作為程式設計師的我們沒有必要關心這個,這些完全可以交由系統去做,故現代的作業系統採用了分段技術,就是將一個程式的程式地址空間分為 資料段 程式指令正文段 堆疊段 還有全域性常量,將這些不同型別的資料放入不同的空間並維護自己的頁表,這樣的幾個獨立的資料空間,空間擴容或減小都有作業系統攜帶分頁程式來管理,程式設計師不需要關心這些。

     

     總結:我們大概說了一下作業系統的記憶體管理機制,其實無非就是通過各種手段去排程交換,讓有限的資源得到最大程度的利用。分頁處理或分段處理也是通過分頁程式或分段程式,將有限的記憶體空間放入最需要的資料。這也是人們在一步一步發展中總結出來的解決問題的辦法的展示。

     

相關文章