存儲管理(二)

.8 換出與丟棄頁面子

      當系統中物理內存減少時,Linux內存管理子系統必須釋放物理頁面。這個任務由核心交換後臺進程(kswapd )來完成。 核心交換後臺進程是一種特殊的核心線程。它是沒有虛擬內存的進程,在物理地址空間上以核心態運行。核心交換後臺進程的名字容易使人誤解,其實它完成的工作比僅僅將頁面交換到系統的交換文件中要多得多。其目標是保證系統中有足夠的空閒頁面來維持內存管理系統運行效率。  此進程由核心的init進程在系統啓動時運行,被核心交換定時器週期性的調用。
      當定時器到時後,交換後臺進程將檢查系統中的空閒頁面數是否太少。它使用兩個變量:free_pages_high 和free_page_low來判斷是否該釋放一些頁面。只要系統中的空閒頁面數大於free_pages_high,核心交換後臺進程不做任何工作;它將睡眠到下一次定時器到時。在檢查中,核心交換後臺進程將當前被寫到交換文件中的頁面數也計算在內,它使用nr_async_pages來記錄這個數值;當有頁面被排入準備寫到交換文件隊列中時,它將遞增一次,同時當寫入操作完成後遞減一次。如果系統中的空閒頁面數在free_pages_high甚至 free_pages_low以下時,核心交換後臺進程將通過三個途徑來減少系統中使用的物理頁面的個數:

  減少緩衝與頁面cache的大小,
  將系統V類型的內存頁面交換出去,
  換出或者丟棄頁面。
  如果系統中空閒頁面數低於free_pages_low,核心交換後臺進程將在下次運行之前釋放6個頁面。否則它只釋放3個。以上三種方法將依次使用直到系統釋放出足夠的空閒頁面。當核心交換後臺進程試圖釋放物理頁面時它將記錄使用的最後一種方法。下一次它會首先運行上次最後成功的算法。
  當釋放出足夠頁面後,核心交換後臺進程將再次睡眠到下次定時器到時。如果導致核心交換後臺進程釋放頁面的原因是系統中的空閒頁面數小於free_pages_low,則它只睡眠平時的一半時間。一旦空閒頁面數大於 free_pages_low則核心交換進程的睡眠時間又會延長。
  3.8.1 減少Page Cache和Buffer Cache的大小
  Page Cache和Buffer cache中的頁面將被優先考慮釋放到free_area數組中。Page Cache中包含的是內存映射文件的頁面,其中有些可能是不必要的,它們浪費了系統的內存。而Buffer Cache中包含的是從物理設備中讀寫的緩衝數據,有些可能也是不必要的。當系統中物理頁面開始耗盡時,從這些cache中丟棄頁面比較簡單(它不需要象從內存中交換一樣,無須對物理設備進行寫操作)。除了會使對物理設備及內存映射文件的訪問速度降低外,頁面丟棄策略沒有太多的副作用。如果策略得當,則所有進程的損失相同。
  每次核心交換後臺進程都會嘗試去壓縮這些cache。
  它首先檢查mem_map頁面數組中的頁面塊看是否有可以從物理內存中丟棄出去的。當系統中的空閒頁面數降低 到一個危險水平時,核心後臺交換進程頻繁進行交換,則檢查的頁面塊一般比較大。檢查的方式爲輪轉,每次試圖壓縮內存映象時,核心後臺交換進程總是檢查不同的頁面塊。這是衆所周知的clock算法,每次在整個mem_map頁面數組中對頁面進行檢查。
  核心後臺交換進程將檢查每個頁面看是否已經被page cache或者buffer cache緩衝。讀者可能已經注意到共享頁面不在被考慮丟棄的頁面之列,這種頁面不會同時出現在這兩種cache中。如果頁面不在這兩者中任何一種之中時,它將檢查mem_map頁面數組中的下一個頁面。
  緩存在buffer cache(或者頁面中的緩衝被緩存)中的頁面可以使緩衝分配和回收更加有效。內存壓縮代碼將 力圖釋放在受檢頁面中包含的緩衝區。
  如果頁面中包含的所有緩衝區都被釋放,這個頁面也將被釋放。如果受檢頁面在Linux的page cache中,則它會從page cache中刪除並釋放。
  如果釋放出來了足夠的頁面,核心交換後臺進程將等待到下一次被喚醒。這些被釋放的頁面都不是任何進程虛擬內存的一部分,這樣無須更新頁表。如果沒有足夠的緩衝頁面丟棄則交換進程將試圖將一些共享頁面交換出去。
  3.8.2 換出系統V內存頁面
  系統V共享內存是一種用來在進程之間通過共享虛擬內存來實現進程通訊的機制。進程是如何共享內存將在IPC 一章中詳細討論。現在只需要說明系統V共享內存的任何區域都可以用一個shmid_ds數據結構來表示就足夠了。 此結構包含一個指向vm_area的鏈表指針,vm_area是爲每個共享此虛擬內存區域設計的結構。它們之間通過 vm_next_shared和vm_prev_shared指針來連接。每個shmid_ds數據結構包含一個頁表入口,每個入口描敘物理頁面與共享虛擬頁面之間的映射關係。
  核心交換後臺進程同樣使用clock算法來將系統V共享內存頁面交換出去。
  每次運行時,它要記得哪個共享虛擬內存區域的哪個頁面是最後一個被交換出去的。兩個索引可以協助它完成這項工作,其一是一組shmid_ds數據結構的索引,另一個是系統V共享內存區域的頁表入口鏈表的索引。 這能夠保證對系統V共享內存區域作出公平的選擇。
  由於對於給定的系統V共享虛擬內存的物理頁面框號被保存在所有共享此虛擬內存區域進程的頁表中,核心 交換後臺進程必須同時修改所有的頁表以表示頁面不再在內存而在交換文件中。對於每個要交換出去的共享 頁面,核心交換後臺進程可以在每個共享進程的頁表中的頁表入口中找到它們(通過vm_area_struct數據結 構)。如果對應此係統V共享內存的頁面的進程頁表入口是有效的,它可以將其轉變成無效,這樣換出頁表入口和共享頁面的用戶數將減一。換出系統V共享頁表入口的格式中包含一個對應於一組shmid_ds數據結構的索引以及一個對系統V共享內存區域的頁表入口索引。
  如果所有共享進程的頁表都被修改後此頁面的記數爲0則共享頁面可以被寫到交換文件中。同樣指向此係統V共享內存區域的shmid_ds數據結構鏈表中的頁表入口也被換出頁表入口代替。換出頁表入口雖然無效但是它包含一組打開的交換文件的索引,同時還能找到換出頁面在文件中的偏移。當頁面重新被帶入物理內存時,這些信息十分有用。
  3.8.3 換出和丟棄頁面
  交換後臺進程依次檢查系統中的每個進程以確認誰最適合交換出去。
  比較好的候選者是那些可以被交換出去(有些是不可被交換出去的)並且只有一個或者幾個頁面在內存中的進程。只有那些包含的數據無法檢索的頁面纔會從物理內存中交換到系統交換文件中去。
  可執行映象的許多內容都可以從映象文件中讀出並且可以很容易重讀出來。例如,映象中的可執行指令不能被映象本身修改,所以決不會寫到交換文件中去。這些頁面直接丟棄就可以。當進程再次引用它們時,只需要從可執行映象文件中讀入內存即可。
  一旦確定了將要被交換出去的進程,交換後臺進程將搜索其整個虛擬內存區域以找到那些沒有共享或者加鎖的區域。
  Linux並不會將選中的進程的整個可交換頁面都交換出去,它只刪除一小部分頁面。
  如果內存被加鎖則頁面不能被交換或者丟棄。
  Linux交換算法使用頁面衰老算法。每個頁面有一個計數器來告訴核心交換後臺進程這個頁面是否值得交換出 去(此計數器包含在mem_map_t結構中)。當頁面沒有使用或者沒有找到時將會衰老;交換後臺進程僅僅交換 出那些老頁面。缺省操作是:當頁面被首次分配時,其年齡初始值爲3,每次引用其年齡將加3,最大值爲20。 每次核心交換後臺進程運行它來使頁面衰老-將年齡減1。這個缺省操作可以改變並且由於這個原因它們被存儲在swap_control數據結構中。
  如果頁面變老了(age=0),則交換後臺進程將進一步來處理它。dirty頁面可以被交換出去。Linux在PTE中使 用一個硬件相關位來描敘頁面的這個特性(見圖3.2)。然而不是所有的dirty頁面都有必要寫入到交換文件 中去。進程的每個虛擬內存區域可能有其自身的交換操作(由vm_area_struct結構中的vm_ops指針表示),在 交換時使用的是這些方法。否則,交換後臺進程將在交換文件中分配一個頁面並將頁面寫到設備上去。
  頁面的頁表入口被標誌成無效但是它包含了頁面在在交換文件中位置的信息,包括一個表示頁面在交換文件中位置的偏移值以及使用的是哪個交換文件。但是不管使用的是哪種交換算法,以前那個物理頁面將被標誌成空閒並放入free_area中。Clean(或者not dirty)的頁面可以丟棄同時放入free_area以備重新使用。
  如果有足夠的可交換進程頁面被交換出去或丟棄,則交換後臺進程將再次睡眠。下次它醒來時將考慮系統中 的下一個進程。通過這種方法,交換後臺進程一點一點地將每個進程的可交換或可丟棄物理頁面收回知道系 統再次處於平衡狀態。這比將整個進程交換出去要公平得多。
  3.9 The Swap Cache
  當將頁面交換到交換文件中時,Linux總是避免頁面寫,除非必須這樣做。當頁面已經被交換出內存但是當有進程再次訪問時又要將它重新調入內存。只要頁面在內存中沒有被寫過,則交換文件中的拷貝是有效的。
  Linux使用swap cache來跟蹤這些頁面。這個swap cache是一個頁表入口鏈表,每個對應於系統中的物理頁面。這是一個對應於交換出頁面的頁表入口並且描敘頁面放置在哪個交換文件中以及在交換文件中的位置。 如果swap cache入口爲非0值,則表示在交換文件中的這一頁沒有被修改。如果此頁被修改(或者寫入)。 則其入口從swap cache中刪除。
  當Linux需要將一個物理頁面交換到交換文件時,它將檢查swap cache,如果對應此頁面存在有效入口,則 不必將這個頁面寫到交換文件中。這是因爲自從上次從交換文件中將其讀出來,內存中的這個頁面還沒有被修改。
  swap cache中的入口是已換出頁面的頁表入口。它們雖被標記爲無效但是爲Linux提供了頁面在哪個交換文件中以及文件中的位置等信息。
  3.10 頁面的換入
  保存在交換文件中的dirty頁面可能被再次使用到,例如,當應用程序向包含在已交換出物理頁面上的虛擬內存區域寫入時。對不在物理內存中的虛擬內存頁面的訪問將引發頁面錯誤。由於處理器不能將此虛擬地址轉換成物理地址,處理器將通知操作系統。由於已被交換出去,此時描敘此頁面的頁表入口被標記成無效。處理器不能處理這種虛擬地址到物理地址的轉換,所以它將控制傳遞給操作系統,同時通知操作系統頁面錯誤的地址與原因。這些信息的格式以及處理器如何將控制傳遞給操作系統與具體硬件有關。
  處理器相關頁面錯誤處理代碼將定位描敘包含出錯虛擬地址對應的虛擬內存區域的vm_area_struct數據結構。 它通過在此進程的vm_area_struct中查找包含出錯虛擬地址的位置直到找到爲止。這些代碼與時間關係重大,進程的vm_area_struct數據結構特意安排成使查找操作時間更少。
  執行完這些處理器相關操作並且找到出錯虛擬地址的有效內存區域後,頁面錯處理過程其餘部分和前面類似。
  通用頁面錯處理代碼爲出錯虛擬地址尋找頁表入口。如果找到的頁表入口是一個已換出頁面,Linux必須將其 交換進入物理內存。已換出頁面的頁表入口的格式與處理器類型有關,但是所有的處理器將這些頁面標記成無效並把定位此頁面的必要信息放入頁表入口中。Linux利用這些信息以便將頁面交換進物理入內存。
  此時Linux知道出錯虛擬內存地址並且擁有一個包含頁面位置信息的頁表入口。vm_area_struct數據結構可能包含將此虛擬內存區域交換到物理內存中的子程序:swapin。如果對此虛擬內存區域存在swapin則Linux會使用它。這是已換出系統V共享內存頁面的處理過程-因爲已換出系統V共享頁面和普通的已換出頁面有少許不同。如果沒有swapin操作,這可能是Linux假定普通頁面無須特殊處理。
  系統將分配物理頁面並將已換出頁面讀入。關於頁面在交換文件中位置信息從頁表入口中取出。
  如果引起頁面錯誤的訪問不是寫操作則頁面被保留在swap cache中並且它的頁表入口不再標記爲可寫。如果 頁面隨後被寫入,則將產生另一個頁面錯誤,這時頁面被標記爲dirty,同時其入口從swap cache中刪除。 如果頁面沒有被寫並且被要求重新換出,Linux可以免除這次寫,因爲頁面已經存在於交換文件中。
  如果引起頁面從交換文件中讀出的操作是寫操作,這個頁面將被從swap cache中刪除並且其頁表入口被標記 成dirty且可寫。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章