Memory Management (內存管理)
內存管理子系統是操作系統的重要部分
虛擬內存不僅僅讓你的計算機內存顯得更多
Large Address Spaces (巨大的地址空間)操作系統使系統顯得擁有比實際更大量的內存
< Protection (保護)系統中的每一個進程都有自己的虛擬地址空間。這些虛擬的地址空間是相互完全分離的,所以運行一個應用程序的進程不會影響另外的進程。TW.wiNGwIT.CoM另外,硬件的虛擬內存機制允許對內存區寫保護。這可以防止代碼和數據被惡意的程序覆蓋。
< Memory Mapping (內存映射)內存映射用來將映像和數據映射到進程的地址空間。用內存映射,文件的內容被直接連結到進程的虛擬地址空間。
< Fair Physics Memory Allocation (公平分配物理內存)內存管理子系統允許系統中每一個運行中的進程公平地共享系統的物理內存
Shared Virtual Memory (共享虛擬內存)雖然虛擬內存允許進程擁有分離(虛擬)的地址空間,有時你也需要進程之間共享內存。例如,系統中可能有多個進程運行命令解釋程序 < bash 。雖然可以在每一個進程的虛擬地址空間都擁有一份 bash 的拷貝,更好的是在物理內存中只擁有一份拷貝,所有運行 bash 的進程共享代碼。動態連接庫是多個進程共享執行代碼的另一個常見例子。共享內存也可以用於進程間通訊 < (IPC) 機制,兩個或多個進程可以通過共同擁有的內存交換信息。 Linux 系統支持系統 V 的共享內存 IPC 機制。
3.1 An Abstract Model of Virtual Memory (虛擬內存的抽象模型)
在考慮 Linux 支持虛擬內存的方法之前,最好先考慮一個抽象的模型,以免被太多的細節搞亂。
在進程執行程序的時候,它從內存中讀取指令並進行解碼。解碼指令也許需要讀取或者存儲內存特定位置的內容,然後進程執行指令並轉移到程序中的下一條指令。進程不管是讀取指令還是存取數據都要訪問內存。
在一個虛擬內存系統中,所有的地址都是虛擬地址而非物理地址。處理器通過操作系統保存的一組信息將虛擬地址轉換為物理地址。
為了讓這種轉換更簡單,將虛擬內存和物理內存分為適當大小的塊,叫做頁( < page )。頁的大小一樣。(當然可以不一樣,但是這樣一來系統管理起來比較困難)。 Linux 在 Alpha AXP 系統上使用 8K 字節的頁,而在 Intel x86 系統上使用 4K 字節的頁。每一頁都賦予一個唯一編號: page frame number(PFN 頁編號 ) 。在這種分頁模型下,虛擬地址由兩部分組成:虛擬頁號和頁內偏移量。假如頁大小是 < 4K ,則虛擬地址的位 < 11 到 < 0 包括頁內偏移量,位 < 12 和以上的位是頁編號。每一次處理器遇到虛擬地址,它必須提取出偏移和虛擬頁編號。處理器必須將虛擬頁編號轉換到物理的頁,並訪問物理頁的正確偏移處。為此,處理器使用了頁表( < page tables )。
圖 3.1 顯示了兩個進程的虛擬地址空間,進程 X 和進程 Y ,每一個進程擁有自己的頁表。這些頁表將每一個進程的虛擬頁映射到內存的物理頁上。圖中顯示進程 < X 的虛擬頁號 < 0 映射到物理頁號 < 1 ,而進程 < Y 的虛擬頁編號 < 1 映射到物理頁號 < 4 。理論上頁表每一個條目包括以下信息:
有效標志 表示頁表本條目是否有效
本頁表條目描述的物理頁編號
訪問控制信息 描述本頁如何使用:是否可以寫?是否包括執行代碼?
頁表通過虛擬頁標號作為偏移來訪問。虛擬頁編號 5 是表中的第 6 個元素( 0 是第一個元素)
要將虛擬地址轉換到物理地址,處理器首先找出虛擬地址的頁編號和頁內偏移量。使用 < 2 的冪次的頁尺寸,可以用掩碼或移位簡單地處理。再一次看圖 3.1 ,假設頁大小是 0x2000 (十進制 8192 ),進程 Y 的虛擬地址空間的地址是 0x2194 ,處理器將會把地址轉換為虛擬頁編號 1 內的偏移量 0x194 。
處理器使用虛擬頁編號作為索引在進程的頁表中找到它的頁表的條目。如果該條目有效,處理器從該條目取出物理的頁編號。如果本條目無效,就是進程訪問了它的虛擬內存中不存在的區域。在這種情況下,處理器無法解釋地址,必須將控制權傳遞給操作系統來處理。
處理器具體如何通知操作系統進程在訪問無法轉換的無效的虛擬地址,這個方式是和處理器相關的。處理器將這種信息( < page fault )進行傳遞,操作系統得到通知,虛擬地址出錯,以及出錯的原因。
假設這是一個有效的頁表條目,處理器取出物理頁號並乘以頁大小,得到了物理內存中本頁的基礎地址。最後,處理器加上它需要的指令或數據的偏移量。
再用上述例子,進程 Y 的虛擬頁編號 1 映射到了物理頁編號 4 (起始於 0x8000 , 4x 0x2000 ),加上偏移 0x194 ,得到了最終的物理地址 0x8194 。
通過這種方式將虛擬地址映射到物理地址,虛擬內存可以用任意順序映射到系統的物理內存中。例如,圖 < 3.1 中,虛擬內存 < X 的虛擬頁編號映射到了物理頁編號 < 1 而虛擬頁編號 < 7 雖然在虛擬內存中比虛擬頁 < 0 要高,卻映射到了物理頁編號 < 0 。這也演示了虛擬內存的一個有趣的副產品:虛擬內存頁不必按指定順序映射到物理內存中。
3.1.1 Demand Paging
因為物理內存比虛擬內存少得多,操作系統必須避免無效率地使用物理內存。節省物理內存的一種方法是只加載執行程序正在使用的虛擬頁。例如:一個數據庫程序可能正在數據庫上運行一個查詢。在這種情況下,並非所有的數據必須放到內存中,而只需要正被檢查的數據記錄。如果這是個查找型的查詢,那麼加載程序中增加記錄的代碼就沒什麼意義。這種進行訪問時才加載虛擬頁的技術叫做 < demand paging 。
當一個進程試圖訪問當前不在內存中的虛擬地址的時候處理器無法找到引用的虛擬頁對應的頁表條目。例如:圖 < 3.1 中進程 < X 的頁表中沒有虛擬頁 2 的條目,所以如果進程 < X 試圖從虛擬頁 < 2 中的地址讀取時,處理器無法將地址轉換為物理地址。這時處理器通知操作系統發生 page fault 。
如果出錯的虛擬地址無效意味著進程試圖訪問它不應該訪問的虛擬地址。也許是程序出錯,例如向內存中任意地址寫。這種情況下,操作系統會中斷它,從而保護系統中其他的進程。
如果出錯的虛擬地址有效但是它所在的頁當前不在內存中,操作系統必須從磁盤映像中將相應的頁加載到內存中。相對來講磁盤存取需要較長時間,所以進程必須等待直到該頁被取到內存中。如果當前有其他系統可以運行,操作系統將選擇其中一個運行。取到的頁被寫到一個空閒的頁面,並將一個有效的虛擬頁條目加到進程的頁表中。然後這個進程重新運行發生內存錯誤的地方的機器指令。這一次虛擬內存存取進行時,處理器能夠將虛擬地址轉換到物理地址,所以進程得以繼續運行。
Linux 使用 < demand paging 技術將可執行映像加載到進程的虛擬內存中。當一個命令執行時,包含它的文件被打開,它的內容被映射到進程的虛擬內存中。這個過程是通過修改描述進程內存映射的數據結構來實現,也叫做內存映射( < memory mapping )。但是,實際上只有映像的第一部分真正放在了物理內存中。映像的其余部分仍舊在磁盤上。當映像執行時,它產生 < page fault , < Linux 使用進程的內存映像表來確定映像的那一部分需要加載到內存中執行。
3.1.2 Swapping (交換)
如果進程需要將虛擬頁放到物理內存中而此時已經沒有空閒的物理頁,操作系統必須廢棄物理空間中的另一頁,為該頁讓出空間。
如果物理內存中需要廢棄的頁來自磁盤上的映像或者數據文件,而且沒有被寫過所以不需要存儲,則該頁被廢棄。如果進程又需要該頁,它可以從映像或數據文件中再次加載到內存中。
但是,如果該頁已經被改變,操作系統必須保留它的內容以便以後進行訪問。這種也叫做 < dirty page ,當它從物理內存中廢棄時,被存到一種叫做交換文件的特殊文件中。因為訪問交換文件的速度和訪問處理器以及物理內存的速度相比很慢,操作系統必須判斷是將數據頁寫到磁盤上還是將它們保留在內存中以便下次訪問。
如果決定哪些頁需要廢棄或者交換的算法效率不高,則會發生顛簸( < thrashing )。這時,頁不斷地被寫到磁盤上,又被讀回,操作系統過於繁忙而無法執行實際的工作。例如在圖 < 3.1 中,如果物理頁號 < 1 經常被訪問,那麼就不要將它交換到硬盤上。進程正在使用的也叫做工作集 (working set) 。有效的交換方案應該保證所有進程的工作集都在物理內存中。
Linux 使用 < LRU ( Least Recently Used 最近最少使用)的頁面技術來公平地選擇需要從系統中廢棄的頁面。這種方案將系統中的每一頁都賦予一個年齡,這個年齡在頁面存取時改變。頁面訪問越多,年紀越輕,越少訪問,年紀越老越陳舊。陳舊的頁面是交換的好候選。
3.1.3 Shared Vitual Memory (共享虛擬內存)
虛擬內存使多個進程可以方便地共享內存。所有的內存訪問都是通過頁表,每一個進程都有自己的頁表。對於兩個共享一個物理內存頁的進程,這個
From:http://tw.wingwit.com/Article/program/Oracle/201311/16784.html