LINUX內存管理子系統是採用請求調頁式的虛擬存儲器技術實現的。在32位硬件平臺上,LINUX邏輯地址爲32位,因此每個進程的虛擬地址空間爲4GB,操作系統佔用了高端的1GB,低端的3GB則留給用戶程序使用。
對於每個進程,LINUX使用mm_struct結構體來描述進程使用的地址空間的各種信息。在每個進程PCB(task_struct)中包含一個mm_struct的指針指向本進程的mm_struct。每個進程與用戶空間相關的各種信息都存放在mm_struct結構體中,其中包含本進程的頁目錄表的地址,本進程的用戶區組成情況等重要信息。
每個進程的用戶區由一組vm_area_struct結構體組成的鏈表來描述。每個段如代碼段、數據段、棧段等。
分頁模型:
LINUX採用4級頁表結構。第一級頁表的起始地址保存在PCB中,頁表中的每個表項保存了下級頁表的頁面號(即起始地址)。
爲了實現跨平臺運行,LINUX提供了一系列轉換宏使得內核可以訪問特定進程的頁表。
內存映射
可執行文件內容僅僅映射到了對應進程的虛擬地址空間中,並沒有調入物理內存。當程序開始運行並使用到這部分時,linux才通過缺頁中斷把他們從磁盤上調入內存。這種將文件連接到進程虛擬地址空間的過程稱爲內存映射。
物理內存模型:
適應NUMA硬件結構,LINUX建立物理內存模型,對於一個CPU來說,使用性能相同的一段內存空間被成爲一個節點。
物理頁面的分配:
LINUX使用free_area數組來管理空閒頁面,每一個區域都有一套這樣的管理結構。每個元素含有兩個重要指針:一個指向一個位圖區域;而另一個指向由page結構體(頁面信息)作爲元素的雙向鏈表。
BUDDY(夥伴)算法:管理頁面的分配和回收。以2的冪次方作爲單位來管理內存。
頁面回收:解決的關鍵問題就是如何快速地確定回收的頁面能否與已經存在的相鄰空閒頁面組成更大的空閒頁塊。free_area數組中的每個元素指向的位圖正是用於這一目的。當頁面塊被釋放時,代碼將通過位圖檢查是否有相同大小的相鄰或者buddy內存塊存在。如果有,則將它們結合起來形成一個大小爲原來兩倍的新空閒塊。
SLab緩存管理:buddy只適合對大塊內存的請求。對於需要小內存區的請求,如果也按照頁面爲單位分配,將是極大浪費內存資源。
slab分配器算法:
設計目標:
對象服用、硬件cache利用率。
頁面換出或丟棄
爲了保證進程需要頁面時能夠及時申請到足夠的物理內存,LINUX利用內核線程kswapd來定期檢查系統內的空閒物理內存總量。
kswapd通過以下三個途徑來減少系統中使用的物理頁面的個數:
減少緩存與頁面cache的大小;
將系統V類型的共享內存頁面交換出去;
換出或者丟棄屬於進程用戶空間的頁面。
(轉載)髒頁-linux內核中的概念,因爲硬盤的讀寫速度遠趕不上內存的速度,系統就把讀寫比較頻繁的數據事先放到內存中,以提高讀寫速度,這就叫高速緩存,linux是以頁作爲高速緩存的單位,當進程修改了高速緩存裏的數據時,該頁就被內核標記爲髒頁,內核將會在合適的時間把髒頁的數據寫到磁盤中去,以保持高速緩存中的數據和磁盤中的數據是一致的。
交換cache
當頁面交換到交換空間時,LINUX總是避免頁面寫,除非必須這樣做。只要頁面在內存中沒有被寫過,則交換空間中的複製是有效的。LINUX使用交換緩存來跟蹤這些頁面,爲一個頁表入口鏈表,每個對應於系統中的物理頁面。當LINUX需要將一個物理頁面交換到交換空間時,它將檢查交換緩存,如果對應此頁面存在有效入口,則不必將這個頁面寫到交換空間中。因爲自從上次從交換空間中將其讀出來,內存中的這個頁面還沒有被修改。