Linux是一個遵循POSIX(Portable Operating System Interface)标準的作業系統,它繼承了UNIX系統優秀的設計思想,擁有簡練、容錯強、高效而且穩定的核心。此外Linux還具備其他作業系統所不能比拟的優點。①:完全免費;②:核心源代碼完全公開。
Linux2.4核心擁有一個功能完備的記憶體管理子系統,它增加了對NUMA(非均勻存儲結構)體系結構的支援并且使用了基于區(ZONE)的實體記憶體管理方法,進而保持了實體上連續分布、而邏輯上統一的記憶體模式和傳統的共享記憶體程式設計模型,使得系統的性能得以極大的擴充。這樣Linux不僅能夠滿足傳統的桌面應用,而且還能滿足高端伺服器市場的需要。目前,Linux不僅在Internet伺服器上表現出色,而且還可以勝任大型資料庫系統的伺服器。
二:Linux存儲管理的基本架構
Linux核心采用虛拟頁式存儲管理,采用三次映射機制實作從線性位址到實體位址的映射。其中PGD為頁面目錄,PMD為中間目錄,PT為頁面表。具體的映射過程為:
⑴從CR3寄存器中找到PGD基位址;
⑵以線性位址的最高位段為下标,在PGD中找到指向PMD的指針;
⑶以線性位址的次位段為下标,在PMD中找到指向PT的指針;
⑷同理,在PT中找到指向頁面的指針;
⑸線性位址的最後位段,為在此頁中的偏移量,這樣就完成了從線性位址到實體位址的映射過程。
32位的微機平台如Intel的X86采用段頁式的兩層映射機制,而64位的微處理器采用三級分頁。對于傳統的32位平台,Linux采用讓PMD(中間目錄)全0來消除中間目錄域,這樣就把Linux邏輯上的三層映射模型落實到X86結構實體上的二層映射,進而保證了Linux對多種硬體平台的支援。
三:Linux對虛拟記憶體的管理
虛拟記憶體不僅可以解決記憶體容量的問題,還可以提供以下附加的功能:大位址空間;程序保護;記憶體映射;靈活的實體記憶體配置設定;共享虛拟記憶體。
Linux對虛拟記憶體的管理以程序為基礎。32位的線性位址映射的4G的虛拟空間中,從0XC0000000到0XFFFFFFFF的1G空間為所用程序所共享的核心空間,每個程序都有自己的3G使用者空間。
Linux的虛拟記憶體管理需要各種機制的支援,首先記憶體管理程式通過映射機制把使用者程式的邏輯位址映射到實體位址,在使用者程式運作時時如果發現程式中要用的虛拟位址沒有對應的實體位址,就發出請頁要求①:如果有空閑的記憶體可供配置設定,就請求配置設定記憶體②,并把正在使用的實體頁記錄在頁緩存中③,如果沒有足夠的記憶體配置設定,就調用交換機制,騰出一部分記憶體④⑤。另外在位址映射中要通過TLB(翻譯後援存儲器)來尋找實體頁⑧,交換機制中要用到交換緩存⑥,并且把實體頁内容交換到交換檔案中也要修改頁表來映射檔案位址⑦。
一個程序的虛拟位址映射靠三個資料結構來描述:mm_struct、vm_area_struct、page。其中mm_struct結構用來描述一個程序的虛拟記憶體;vm_area_struct描述一個程序的虛拟位址區域,在這個區域中的所有頁面具有相同的通路權限和一些屬性;page描述一個具體的實體頁面。
當程序通過系統調用動态配置設定記憶體時,Linux首先配置設定一個vm_area_struct結構,并連結到程序的虛拟記憶體連結清單,當後續指令通路這一記憶體區域時,産生缺頁異常。系統處理時,通過分析缺頁原因、操作權限之後,如果頁面在交換檔案中,則進入do_page_fault()中恢複映射的代碼,重建立立映射關系。如果因為頁面不再記憶體中,則Linux會配置設定新的實體頁,并建立映射關系。
當實體記憶體出現不足時,就需要換出一些頁面。Linux采用LRU(Least Recently Used最近最少使用)頁面置換算法選擇需要從系統中換出的頁面。系統中每個頁面都有一個“age”屬性,這個屬性會在頁面被通路的時候改變。Linux根據這個屬性選擇要回收的頁面,同時為了避免頁面“抖動”(即剛釋放的頁面又被通路),将頁面的換出和記憶體頁面的釋放分兩步來做,而在真正釋放的時候僅僅隻寫回“髒”頁面。這一任務由交換守護程序kswapd完成。free_pages_high,free_pages_low是衡量系統中現有空閑頁的标準,當系統中空閑頁的數量少于free_pages_high,甚至少于free_pages_low時,kswapd程序會采用三種方法來減少系統正在使用的實體頁的數量。①調用shrink_mmap()減少buffer cache和page cache的大小;②調用shm_swap()将system V共享記憶體頁交換到實體記憶體;③調用swap_out()交換或丢棄頁。
圖1.3給出了頁面置換管理框圖。其中①代表:refill_inactive_scan(),它的任務是掃描活躍頁面隊列,從中找到可以轉入不活躍狀态的頁面;②代表:page_launder()它把已經轉入不活躍狀态的“髒”頁面“洗淨”,使它們成為立即可以配置設定的頁面;③代表:reclaim_page()用于從頁面管理區的不活躍淨頁面隊列中回收頁面。
kswapd是被定期喚醒的,首先檢查記憶體中可供配置設定或周轉的實體頁面是否短缺,若需要回收頁面,則按順序循環檢查緩沖區、共享記憶體、程序獨占的記憶體,遇到滿足條件的頁面,即将它釋放。如果已釋放了足夠的頁面,kswapd重新睡眠,直到下一次被重新喚醒。
四:Linux對實體記憶體的管理
Linux2.4核心加入了對NUMA的支援,如果系統是NUMA結構的處理機系統,則實體記憶體被劃分為三個層次來管理:存儲節點(Node),管理區(Zone),頁面(Page)。處理器的本地記憶體組成的區域叫做一個節點(Node),它通過pglist_data資料結構來描述。各個節點的實體記憶體根據不同的作用又分為ZONE_DMA、ZONE_NORMAL、ZONE_HIGH,ZONE_DMA面積小,且專供DMA使用,ZONE_NORMAL則供大多數的程式使用,對于ZONE_HIGH僅僅隻有頁面緩存以及使用者程序能夠使用該區域的空間。每個管理區對應一個free_area數組來組織空閑頁面隊列,該數組的每一項描述某一種頁塊的資訊,第一個元素描述大小為1頁的記憶體塊的資訊,第二個元素描述大小為2 頁的記憶體塊的資訊,依此類推,所描述的頁塊大小以 2 的倍數增加。free_area 數組的定義如下:
Typedef struct free_area_struct{
Struct list_head free_list;
Unsigned int *map;
}free_area_t;
list_head是一個雙向指針結構,在這裡用于将實體頁塊結構mem_map_t 連結成一個雙向連結清單,而map則是記錄這種頁塊組配置設定情況的位圖,例如,位圖的第N位為1,表明第N個頁塊是空閑的。
頁配置設定代碼使用向量表free_area來配置設定和回收實體頁。系統初始化時,free_area數組也被賦了初值。也就是說,系統中所有可用的空閑實體頁塊都已經被加到了free_area數組中。
Linux使用Buddy最先比對算法來進行頁面的配置設定和回收,并且必須按2的幂次方進行配置設定。如圖1.4所示,比如要配置設定大小為2k的空閑塊,如果系統中有足夠的空閑塊,頁面配置設定代碼首先在free_area中查找相應大小的空閑塊,如果找到則配置設定。如果沒有則查找下一尺寸(2倍于請求大小)的頁面塊,繼續這一過程直到找到可以配置設定的頁面,按要求配置設定之後,将剩餘的空閑塊仍然按照2的幂次方劃分後鍊入适當的空閑塊中。與配置設定算法相反,頁面回收時總是試圖将相鄰的空閑頁面組合成更大尺寸的空閑塊。這裡先給出“夥伴”要滿足的三個條件:①兩個塊大小相同;②兩個塊實體位址連續;③兩個塊從同一大塊中分離出來。在使用者釋放記憶體時,判斷“夥伴”是否是空閑塊。若否,則隻要将釋放的空閑塊簡單的插入相應的free_area中。若是,則需要在free_area中删除其夥伴關系,然後再判斷合并後的空閑塊的夥伴關系,依次重複,直到歸并後的空閑塊沒有夥伴關系或合并到最大塊時将其插入到free_area中。
五:緩存和重新整理機制
為了更好的發揮系統性能,Linux采用了一系列和記憶體管理相關的高速緩存機制:
①緩沖區高速緩存:包含了從裝置中讀取的資料塊或寫入裝置的資料塊。緩沖區高速緩存由裝置标示号和塊索引,是以可以快速找到資料塊。如果資料可以在緩沖區中高速緩存中找到,則不需要從實體塊裝置上讀取,進而加快了通路速度。
②頁高速緩存:這一高速緩存用來加速對磁盤上的映像和資料通路,它用來緩存某個檔案的邏輯内容,并通過檔案VFS索引節點和偏移量通路。當頁從磁盤讀到實體記憶體時,就緩存在頁高速緩存。
③交換高速緩存:用于多個近程共享的頁面被換出到交換區的情況。當頁面交換到交換檔案之後,如果有程序再次通路,它會被重新調入記憶體。
六:小結
Linux是近年來應用的比較多的一個作業系統,廣泛應用于各個行業。而且由于全世界計算機愛好者的支援,Linux也成為世界上發展最快的作業系統。在Linux2.6核心中,對存儲管理子系統進行了一系列的改進,提高了系統的可擴充性,包含了對大型伺服器如NUMA伺服器和Intel伺服器的良好支援。此外,Linux2.6還提供了對無MMU的支援。可見Linux正在不斷的加強對高端伺服器領域以及嵌入式領域的支援。
Linux在其發展過程中不斷的在完善和優化記憶體管理單元的功能和性能。針對具體領域,我們可以根據自己的需要定制Linux核心。而記憶體管理單元作為Linux作業系統的核心部分,在整個系統的運作過程中發揮着舉足輕重的作用。