date: 2014-10-01 19:09linux
在講《x86頁式內存管理》中提到過「頁面交換」。一個系統的物理內存老是有限的,可是運行在其上的進程卻不敢不顧的一味「索取」,爲了解決這種困境,在計算機的發展史上很早就有將內存中的內容與一個專用的磁盤空間交換的技術,即把內存中暫時不用的內容存到磁盤上,爲其餘急用的內容騰出內存空間,到須要時再將磁盤上的內容讀到內存中。數組
在繼續以前,要明確幾個概念。首先「虛存頁面」指虛擬地址空間中一個固定大小,邊界與頁面大小(4KB)對齊的區間及內容。「虛存頁面」最終要落實(映射)到某種物理存儲介質上,這就是「物理頁面」。根據介質的不一樣,「物理頁面」分爲「內存頁面」(在內存中)和「磁盤頁面」(在磁盤上)。當咱們談及(物理)內存頁面的分配和釋放時,指的僅是物理介質;而在談及頁面的換入換出時,指的是頁面中的內容。app
咱們在討論(物理)內存頁面時提到page結構就是內存頁面的戶口,系統在初始化階段,內核根據檢測到的內存的大小,爲每個頁幀創建page結構,造成一個page結構的數組,並用全局變量mem_map指向這個數組,mem_map就像是物理內存的戶口簿,有了這個戶口簿系統就能夠跟蹤到每個頁幀。spa
那麼「磁盤頁面」呢?「磁盤頁面」是如何管理的呢?code
首先,對「磁盤頁面」內核並無對應的結構體,由於磁盤頁面要依附在「交換設備」(一般是磁盤,也能夠是普通文件,設備即文件)上,從內核管理磁盤頁面角度來看,只需知道它在交換設備上的位置,以及該頁面的使用計數(表示該頁面是否被使用,以及有幾個用戶在共享該頁面)便可。一個交換設備上的磁盤頁面確定具備相同的屬性,這些屬性信息從交換設備上獲取便可。於是,內核對磁盤頁面的管理是按交換設備來進行的。交換設備對應的抽象爲swap_info_struct結構,而「磁盤頁面」的定義也是依附在swap_info_struct結構體中。blog
swap_info_struct結構定義以下:進程
<include/linux/swap.h> struct swap_info_struct { unsigned int flags; kdev_t swap_device; spinlock_t sdev_lock; struct dentry * swap_file; struct vfsmount *swap_vfsmnt; unsigned short * swap_map; unsigned int lowest_bit; unsigned int highest_bit; unsigned int cluster_next; unsigned int cluster_nr; int prio; /* swap priority */ int pages; unsigned long max; int next; /* next entry on swap list */ };
linux內核容許使用多個交換設備,因此在內核中還有一個swap_info_struct結構數組swap_info,其定義以下:內存
<include/linux/swap.h> #define MAX_SWAPFILES 8 <mm/swapfile.c> struct swap_info_struct swap_info[MAX_SWAPFILES];
可見,最多可使用8個交換設備。注意這個全局數組swap_info,內核就是經過這個全局數組找到對應的交換設備的。it
就像虛存頁面經過頁面表項pte_t與物理內存頁面創建映射關係同樣,磁盤頁面也有相似的「頁面表項」swp_entry_t。swp_entry_t的定義以下:內存管理
<include/linux/shmem_fs.h> /* * A swap entry has to fit into a "unsigned long", as * the entry is hidden in the "index" field of the * swapper address space. * * We have to move it here, since not every user of fs.h is including * mm.h, but m.h is including fs.h via sched .h :-/ */ typedef struct { unsigned long val; } swp_entry_t;
可見,swp_entry_t也爲32位的整數,與pte_t同樣,swp_entry_t也將32位分段使用,這裏分紅的3段,示意以下:
須要說明:當內存頁面交換到磁盤頁面上以後,對應的頁面表項pte_t就「變身」爲swp_entry_t,「變身」後仍駐留在以前的頁表中,此時虛存頁面被映射到一個磁盤頁面上了。當在用戶空間訪問虛存頁面時,根據CR3一步步找到這個頁面表項(swp_entry_t),MMU發現其bit0爲0,瞭解到該頁面不在內存中,因而觸發頁面異常。咱們在前面分析過頁面異常的處理程序do_page_fault,此種狀況又對應另外一種場景:出錯地址沒有落在空洞中,並且就落在某個虛存區間vma中,內核經過讀取對應的swp_entry_t能夠知道該虛存頁面的去向,而後將其換入到內存中。有興趣的同窗能夠自行一觀。
pte_t與swp_entry_t的關係是如此的密切,內核爲此定義了一組宏:
/* Encode and de-code a swap entry */ #define SWP_TYPE(x) (((x).val >> 1) & 0x3f) #define SWP_OFFSET(x) ((x).val >> 8) #define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) #define pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low }) #define swp_entry_to_pte(x) ((pte_t) { (x).val })