linux下的內存管理

概述

linux內存管理基礎知識,反覆看深入理解linux內核

內存分區


 •位於最低端的 ZONE_DMA 內存區域是爲 ISA 設備保留的,這些設備僅有 16MB
的 DMA 尋址能力。
• ZONE_NORMAL 中的頁面具有 1:1 線性映射的物理地址和邏輯地址。運行在內
核態的代碼可以方便和高效地訪問,內核中大部分數據結構的內存對象都使用
這個區中的內存。
• ZONE_HIGHMEM 來自於 32 位內核的尋址能力限制。一個 32 位指針只能尋
址 4G 字節。Linux 默認按照 1:3 的比例對進程的地址空間進行劃分,其中的
1GB 地址空間保留給內核使用,剩下的 3GB 是一個進程實際可用的虛擬地址
空間。由於 1GB 可用地址空間的限制,不是所有的物理內存都可以被內核
直接訪問。稱內核可以直接訪問的爲低端內存 (low memory),不能直接訪問
的爲高端內存 (high memory)。Linux 在 1GB 線性地址空間中劃出 128MB,主
要用於映射訪問高端內存。因而低端內存區 ( ZONE_NORMAL) 和高端內存區
( ZONE_HIGHMEM) 的分界線就在 1GB-128MB=896MB 處。數量衆多的用戶態
進程申請使用的內存以及內核維護的文件緩存頁面都優先從 ZONE_HIGHMEM
中分配,其次才考慮 ZONE_NORMAL。
• ZONE_DMA32 是爲 64 位系統中的 32 位設備準備的。在一個 64 位 CPU 上運
行的 64 位 Linux 內核或進程本身沒有高端內存的限制,但是系統中仍然可能
存在可選的 32 位設備。這些設備只能在 4GB 的地址空間中進行 DMA 操作,
相應的內存就需要從 ZONE_DMA32 中分配。

內存分配

 
在每個 zone 中, Linux 都維護一個 free_area 數據結構,並使用 Buddy 算法來
管理和分配空閒的頁面。在 Buddy 算法中,內存被劃分爲二的冪次方大小,並按此大
小自然對齊的塊組。Linux 實現的內存分配單位是 2i, i = 0, 1, 2, . . . , MAX_ORDER-1個頁面,其中 MAX_ORDER 的缺省值是 11。如圖2.2所示, free_area 結構的基本組成包括 MAX_ORDER 個鏈表,其中第 i 個鏈表上掛載的是階數爲 i 的空閒頁面組,每個頁面組包含 2i個自然對齊的連續頁面。Buddy 算法另外還維護一個位圖數組,用以快速地檢索空閒頁面在地址空間中的分佈狀況。
當需要從空閒內存池中分配 2i個連續頁面時,算法首先從 free_area 中階數爲 i 的鏈表上獲取空閒頁面組。如果沒有滿足要求的空閒頁面組,則繼續在第 i + 1個鏈表上搜索兩倍於請求大小的內存塊。這個過程將一直持續到找到足夠大的空閒內存塊爲止。如果找到的頁面塊大小 2j大於請求的塊大小 2i,則將其移出第 j 個鏈表,並分割爲大小分別爲 2i, 2i, 2i+1, 2i+2, . . . , 2j¡1的共計 j − i + 1 個內存塊,其中第一個內存塊的大小與請求大小相匹配,可供給申請者使用。其餘的各塊分別加入第 i, i + 1, . . . , j − 1 個鏈表,並相應地更新位圖數組。將大的頁面塊打碎進行分配將增加系統中零碎的空閒內存塊的數目。頁面回收代碼在適當時機下要將相鄰的空閒頁面結合起來形成單一大頁面塊。當頁面塊被釋放時,Buddy 算法將檢查是否有相同大小的相鄰內存塊存在。如果有,並且合併後的內存塊仍然是自然對齊的,則將它們結合起來形成一個大小爲原來兩倍的新空閒塊。每次結合完之後,還要檢查是否可以繼續合併成更大的頁面組。

內存回收

Linux 的內存管理子系統被設計爲最大限度地利用可用的物理內存來緩存數據。因而它僅在 free_area 中維持的少量的空閒頁面。其它即將使用、正在使用和最近被使用過的頁面都排列在鏈表 active_list 或 inactive_list 中。雙鏈表結構的設計初衷是, active_list 用於容納系統所有進程的工作集 (working set),或者被活躍引用的那些頁面; inactive_list 則用於緩存和回收那些不活動的頁面。active_list 和 inactive_list 中的頁面採用最近少使用 (LRU, Least Recently Used) 的原則排隊,其中最近較少使用的頁面被逐步推向隊列的尾部,並最終被內存掃描算法選擇丟棄。這一過程被稱爲頁面的老化 (aging) 和回收 (reclaim)。在三種情況下,需要對上述兩個 LRU 隊列進行掃描,回收其中的不活動頁面,同時向 free_area 補充空閒頁面:
• 如果在某次內存分配操作中,當搜索完 free_area 中的相關鏈表後,仍然未能找到大於或等於請求大小的內存塊,則內存分配失敗。此時需要在當前的進程上下文中立即進行同步的內存掃描,在掃描期間程序必須等待。
• 如果內核檢測到空閒的頁面數過少(由預設值 min_free_kbytes 決定),則喚醒 kswapd 進行異步的內存掃描和回收。
• 在需要大量釋放內存的時候。比如筆記本電腦即將進入休眠 (hibernate),或者用戶通過 /proc/sys/vm/drop_caches 接口要求清空緩存。
在對每一個 zone 的內存掃描中,掃描算法遵循如下規則:
• 在 2.6.24 及之前的版本中,保證對 active_list 和 inactive_list 的掃描速度是同步的:如果在某次內存掃描中,兩個隊列的長度分別爲 La 和 Li ,檢查的頁面數分別爲 Sa 和 Si ,則 La: Sa = Li: Si 。
• 在 2.6.25 及其後續版本中,對不同類型的緩存頁面按不同的優先級進行掃描。
首先,優先掃描 inactive_list,僅當無法獲得足夠數量的空閒頁面時進一步掃描 active_list;其次,優先回收普通頁面,僅在必要時丟棄內存映射頁面 (memory mapped pages)。這一新的策略以犧牲公平性爲代價,以求減少無效掃描的數量以及內存回收操作的代價。這種內存回收效率的優化有利於避免配備大容量內存的服務器在回收內存操作上花費大量的 CPU 時間。
• inactive_list 中的 mmap 頁面如已被引用一次或一次以上,則將其加入 active_list,否則取消映射並立即丟棄該頁面;普通頁面則必須被引用兩次才能避免被丟棄,並且它們在被第二次引用時會被立即移入 active_list。無法被換出的匿名頁面也會被加入 active_list。
• active_list 中曾被引用的 mmap 頁面:正常情況下,放回 active_list的頭部;未被引用的 mmap 頁面以及所有的普通頁面:放入 inactive_list。如果沒有可用的交換空間,則匿名頁面是不可回收的,因而它們會被放回 active_list,以求減少無效掃描的次數。
• 在檢查每個頁面的同時,清除其引用標誌。

同步頁面老化

 
頁面回收算法必須保證對各個 zone 的掃描速度是同步的。即如果兩個 zone 的大小分別爲 L1 和 L2,某次掃描的頁面數分別爲 S1 和 S2,則應保證 L1: S1 = L2: S2。不過 ZONE_DMA 是個例外。它非常小,並且是稀缺資源,因而通常被保留爲 DMA專用內存。
如果不能保證各個 zone 掃描的步調一致,就會造成不同 zone 中頁面的老化速度不一致 (imbalance of aging)。這不但是一種不公平,而且會使內存的使用效率大打折扣。例如在圖2.3中的系統中,包含有兩個大小相同的 zone 和一個被順序訪問的文件。按照正常的內存回收和分配策略,新申請的頁面會交替地從兩個 zone 取得。因而此文件的頁面緩存中的 0-7 頁可能是從 zone 2 中取得的,8-13 頁則來自於 zone 1,最後的頁面 14-19 可能又屬於 zone 2。如果 zone 1 的老化速度比 zone 2 快,則此文件的第 8-13 個頁面會早早地從 zone 1 中被淘汰,同時其他頁面仍會在 zone 2 中駐留較長的一段時間,在此期間,在此文件中就有了一個小小的緩存空洞。如果此時這個文件被再次順序訪問,則到了此處就會引發一個或兩個小 I/O,以補上這個 6頁面的緩存空洞。按照 I/O 時間的簡單計算公式,前者的 I/O 時間大約是 8ms 的訪問時間加上 6 × 4KB ÷ 80MB/s = 0.3ms 的傳輸時間共計 8.3ms,後者的 I/O 時間是8 + 20 × 4KB ÷ 80MB/s = 9ms。因而對於磁盤來說,一個 6 頁面的小 I/O 的跟一個更大的包括 20 頁面的 I/O 所需的時間僅有 8% 的差別。或者說,被提前丟棄的 6 個頁面所可能造成的 I/O 代價與丟棄所有 20 個頁面的 I/O 代價差別不大。這也意味着,一旦緩存中的 6 個頁面被丟棄,剩餘的 14 個頁面就沒有太大的緩存價值了。它們因爲老化速度相對較慢的緣故而繼續逗留在 zone 2 中,基本上是對內存的一種浪費
因而一個總是被順序/完整訪問的文件,它的緩存頁面的老化和回收也應當儘可能保持一種順序/完整性。此類文件的頁面緩存中哪怕是缺失了一個頁面,也會使剩下的臨近緩存頁面失去其大部分緩存價值。這種相關性使某些 I/O 負載對頁面老化的不平衡特別敏感。比如在 mp3 下載、視頻點播等服務中,I/O 負載的類型都是順序服務一些較大尺寸的文件。在這種情況下,頁面老化速度的不均衡會造成普遍性的文件緩存空洞,從而影響到全局的內存使用效率。假設 zone 1 的掃描速度是 zone 2的 n 倍,則 zone 2 尾部的(n-1)/n將伴有緩存空洞,相應的內存就基本上被浪費了。
在一些老版本的 Linux 中,就存在這種 zone 掃描速度的不平衡現象:在每次掃描中,Linux 遍歷系統中所有的 zone,並按比例對它們進行掃描。但是如果順利地在一個 zone 中回收了一定數量的頁面,對這個 zone 的掃描就會提前終止。這就使按zone 大小分配的掃描頁面數量之間的比例關係被破壞,從而會使小的 zone 傾向於被過度掃描。實測表明,這種 zone 之間掃描速度的不平衡可達到 2 : 1 ∼ 3 : 1,可令系統中多達 50% ∼ 66% 的內存緩存被低效率使用。

頁面緩存(page cache)

Linux 內核的虛擬文件系統層 (VFS, Virtual File System) 爲標準文件 I/O 提供統一的緩存機制,以提高常用文件的訪問效率。緩存的內容包括文件的元數據(meta-data) 和數據 (data) 兩大類。
各文件系統通用的元數據主要包括文件內容的相關屬性和文件名。相應的 VFS維護了兩個緩存池:
• icache: 緩存最近打開過的文件 i 節點 (inode)。對文件的 stat 和 open 操作都會打開它的 inode。inode 是 UNIX 文件系統中的一個核心數據結構,用於存儲一個文件、目錄或其它對象的基本屬性。這些屬性包括:大小、屬主、權限、時戳、文件類型等等。inode 的這些屬性描述的是文件的內容而非名字。
• dcache: 緩存最近查找過的文件名和目錄項 (dentry)。爲了加快文件的查找,每一個最近被訪問過的目錄和文件都在 dcache 中緩存一個它的 dentry 對象。一個打開的文件實例會指向一個唯一的 dentry 對象,後者又指向一個唯一的 inode對象。屬於同一個文件系統名字空間 (namespace) 的所有 dentry 對象通過引用關係構成一棵樹。
數據緩存的基本單位是頁面 (page),因而一般稱內核中的文件數據緩存爲頁面緩存 (page cache)。在 x86 體系結構中,頁面大小一般是 4KB。本文將在一些舉例中直接使用這一典型值。
頁面緩存是文件數據在內存中的副本,因此頁面緩存的管理與內存管理系統和文件系統都相關(周應超, 2006):一方面,頁面緩存作爲物理內存的一部分,需要參與物理內存的分配、老化和回收過程;另一方面,頁面緩存中的數據來源於存儲設備上的文件,需要通過文件系統與存儲設備進行讀寫交互。從操作系統的角度考慮,頁面緩存可以看做是內存管理系統與文件系統之間的聯繫紐帶。因此,頁面緩存管理是 Linux 內核的一個重要組成部分,它的性能直接影響着文件系統和內存管理系統的性能。
在 Linux 內核中,文件的每個數據塊對應唯一的一個緩存頁面。這些頁面由內存管理子系統和虛擬文件系統分別通過兩種方式組織起來,以滿足不同的需要。
內存管理爲頁面緩存選擇的數據結構是雙向鏈表。Linux 內核爲每一片物理內存區域 (zone) 維護 active_list 和 inactive_list 兩個雙向鏈表,這兩個 LRU隊列主要用來實現物理內存的老化和回收。這兩個鏈表上除了文件緩存頁面之外,主要還包括匿名頁面 (anonymous page)。匿名頁面中的數據不屬於任何一個磁盤文件,但必要時可以臨時保存到交換設備中去。用戶態進程通過 malloc() 申請的內存、通過 MAP_PRIVATE,MAP_ANONYMOUS 映射的內存和共享內存、以交換設備作爲後備存儲的文件系統 (tmpfs) 等用的都是匿名頁面。
虛擬文件系統用於索引頁面緩存的數據結構是 radix tree (Rao et al., 2005)。 Linux
2.6 引入的 radix tree 可以根據一個文件的字節數偏移量,快速地確認此處的數據緩存頁面是否存在,如果存在的話,獲得該頁面結構的地址。如圖2.4所示,Linux 爲每個文件 inode 都創建一棵 radix tree,用於管理屬於該文件的所有緩存數據頁面,並稱之爲該文件的地址空間 (address space)。搜索樹中的每個節點的分支數缺省爲 64,對於內存較少的嵌入式系統可以配置爲 16。很高的分叉數意味着即使對大型文件,搜索樹的高度也不大,從而可以達到很好的搜索效率。表2.1列出了不同的樹高可以支持的最大頁面數和文件大小。可見對於常見的 1GB 以內文件, height 一般取值僅爲 1 ∼ 3,搜索代價大致上就是同等數量的內存訪問次數。
 
 

頁面緩存預讀

當用戶進程發出一個 read() 系統調用時,內核以頁面爲單位逐次處理讀請求和進行數據傳送。首先在請求文件的地址空間中查找相應的頁面有沒有被緩存。如果有,則不必再次從存儲設備中去讀,直接從該頁面中拷貝數據到用戶緩衝區就可以了。否則就要先申請一個空閒頁面,並且將它插入該文件的地址空間 radix tree 以及該頁面所在 zone 的 inactive_list,然後對新頁面調用 readpage() 函數,向底層發送 I/O 請求,將所需的文件數據塊從存儲設備中讀出來存放在該頁面中,最後再從該頁面中將所需數據複製到用戶緩衝區。
以上是在沒有預讀參與情況下的文件讀取過程。如果適當地對文件 I/O 的大小和時間進行調整優化,往往可以大幅度提高效率。預讀算法預先向頁面緩存中加入頁面併發起 I/O,就可以把應用程序的讀請求與實際的磁盤 I/O 操作兩者分離開來,從而獲得進行 I/O 優化所需的自由度。
 
本文討論的預讀算法的工作上下文如圖2.5所示。在以頁面緩存爲中心的架構中,標準的文件系統讀請求只是簡單的把數據從內核中的頁面緩存拷貝到程序的讀緩衝區,並不直接發起磁盤 I/O。發起 I/O 並往頁面緩存加入數據是預取例程的責任。通常這些內核設施是對上層透明的,應用程序並不知道緩存和預取的存在,因而也不會給預取算法以任何提示。預取算法獨立自主地決定進行預取 I/O 的最佳時機、位置和大小。它的主要決策依據來自於對讀請求和頁面緩存的在線監控。它使用啓發式的算法邏輯來猜測上層程序的 I/O 意圖。
 
如圖2.6所示,預取算法工作於 VFS 層,對上統一地服務於各種文件讀取的系統調用 API,對下獨立於具體的文件系統。當應用程序通過read(),pread(),readv(),aio_read(),sendfile(),splice() 等不同的系統調用接口請求讀取文件數據時,都會進入統一的讀請求處理函數 do_generic_file_read()。這個函數從頁面緩存中取出數據來滿足應用程序的請求,並在適當的時候調用預讀例程進行必要的預讀 I/O。
預讀例程在 Linux 2.6.22 及之前的版本中是 page_cache_readahead(),從2.6.23 開始改爲根據是否同步預讀分別調用 page_cache_sync_readahead()或 page_cache_async_readahead(),進行簡單的判斷和預處理,如有必要再調用 ondemand_readahead() 運行按需預讀算法。
預讀算法發出的預讀 I/O 請求交由 __do_page_cache_readahead() 進行預處理,該函數檢查請求中的每一個頁面是否已經在文件緩存地址空間中,如果沒有的話就申請一個新頁面。如果該新頁面的偏移量正好是預讀參數 async_size指向的位置,則爲該頁面置 PG_readahead 標記。最後,所有的新頁面被傳給 read_pages(),它們在這裏被逐個加入 radix tree 和 inactive_list,並調用所在文件系統的 readpage(),將頁面交付 I/O。當然,文件系統也可以提供自己的 readpages(),實現批量頁面 I/O 的功能。
值得注意的是,Linux 中的預取算法對頁面在塊設備上的位置並不知情。它只是依據頁面在文件中的邏輯偏移量進行預讀決策,並期望每個文件在物理上是連續存儲的。由於不連續的文件存儲會嚴重影響 I/O 效率,Linux 下的主要文件系統都有一個重要的設計目標,即儘可能在各種惡劣條件下保證文件在存儲設備上的順序存儲,把文件中連續的邏輯地址映射到存儲設備中連續的物理地址。因而只要文件系統使用得當,不過份壓榨可用的存儲空間,就不會有嚴重的文件碎片 (fragmentation) 問題。

Read-ahead和Read-around

 
Linux 中的文件操作 API 按其預讀策略可以分爲三類,如圖2.7所示。最常用的文件訪問方式是,通過 read() 等系統調用接口,經由頁面緩存訪問一個磁盤文件。內核對這一標準文件訪問路徑調用通用預讀算法,跟蹤程序的訪問序列,並進行恰當的預讀。
有些應用程序——主要是 ORACLE/DB2 等大型數據庫管理系統——維護自己的數據緩存池,並自主運行緩存和預讀算法。因而它們希望繞過內核維護的頁面緩存及其預讀算法,避免重複緩存和緩存之間的拷貝開銷,並實現對底層 I/O 的最終控制。內核爲這些高級應用提供了直接 I/O(direct I/O) API,以及對裸設備 (raw device)的讀寫操作。
還有一種特別的文件操作方式是對內存映射文件 (memory mapped file) 的讀寫。通過系統調用接口 mmap(),應用程序可以把一個文件的地址空間映射到進程的地址空間中去。之後程序可以直接訪問經過映射的虛擬內存區域來讀寫文件緩存中的相應數據。這種用戶態進程通過內存映射訪問內核中的頁面緩存的方式可以簡化程序設計,並避免內核緩存與應用程序緩存之間的一次內存拷貝。
mmap 文件的緩存頁面是通過頁面請求 (page fault) 機制加載的,其工作過程下:
1. 應用程序調用 mmap(),陷入到內核中後調用 do_mmap_pgoff()。該函數從應用程序的地址空間中分配一段區域,並創建一個 VMA 結構 ( vm_area_struct)指向該區域,並標記它與文件的映射關係,然後返回到應用程序。
2. 當應用程序訪問該 VMA 中的內存時,由於內核尚未在該進程的地址空間中爲相應的邏輯頁面建立頁表項 (PTE, Page Table Entry),會觸發缺頁中斷,進入缺頁中斷處理函數。在缺頁中斷處理函數中,內核找到缺失的邏輯頁面所屬區域的 VMA 結構,判斷出該區域屬於文件映射,於是調用 filemap_fault()讀入相應的緩存頁面,並將頁面地址寫入當前進程的頁表。經過這些步驟之後,應用程序就可以正常訪問相應的數據了。
Linux 在建立文件的內存映像時,僅建立必要的 VMA 結構,其餘的建立頁表項及其對應的物理頁面的工作全部延後到應用程序實際引用該頁面,並觸發缺頁中斷的時候去做;在每次缺頁時,也僅爲當前的請求頁面填入頁表項。這種策略被稱爲按需調頁 (demand paging),它可以極大地減少不必要的浪費。
然而簡單的按需調頁會帶來大量的單頁面小 I/O,導致極低的磁盤 I/O 性能。因而 filemap_fault() 實現了簡單的預取功能。規則如下:
• 發生缺頁中斷時,如果發現頁面緩存中已經有相應的文件頁面,則直接在進程頁表中登記該頁後返回。
• 如果無緩存頁面,則以當前頁面爲中心,預取 ra_pages(=32) 個頁面。不過 Linux 沒有實現完整的預先調頁 (pre-fault) 功能,即將這些預讀的頁面進一步填入進程的頁表中去。只有被實際訪問的頁面纔會被填入當前進程的頁表,成爲一個映射頁面 (mapped page)。映射頁面享有較高的緩存優先級,比普通頁面更不容易被內存管理算法回收。Linux 不進行預先調頁,一方面節省了一些不必要的開銷,另一方面也避免了無關的緩存頁面成爲映射頁面,無謂地佔用更長時間的內存。
• 如果預讀次數比預讀命中次數還多 MMAP_LOTSAMISS=100,則放棄預讀。這一條件是爲了防止出現大量的無效預讀。例如當負載是一些稀疏的隨機讀,在預讀了 MMAP_LOTSAMISS 次後,基本上就會停止預讀。但這一機制僅對大文件和大訪問量有效,小於 100 × 32 × 4 = 12, 800KB 的文件訪問量不能觸發上述停止條件。
綜上所述,Linux 實現了兩種預讀算法:一個適用於常規文件訪問方式的通用read-ahead 算法,和一個適用於 mmap 文件訪問方式的簡單 read-around 算法。兩種預讀的調用路徑如圖2.8所示。其中 read-ahead 算法的設計目標爲支持儘可能多的 I/O負載類型,力求準確地識別出請求序列中的順序成分,並選擇適當的時間和大小進行預讀;而 read-around 算法僅執行一個簡單並且貪婪的預取策略。read-around 算法對於那些以 mmap 方式訪問的程序代碼和數據是非常適用的,因爲它們的 I/O 往往是兼有隨機性和順序性,並且具有很強的引用局域性 (locality of reference) 特徵。
 

預讀API

預取有兩種方案:啓發性的 (heuristic prefetching) 和知情的 (informed prefetching)。前者自動自發的進行預讀決策,對上層應用是透明的,但是對算法的要求較高,存在命中率的問題。read-ahead 和 read-around 兩種算法就屬於這一範疇。後者則提供一套預讀 API 接口,以便由上層程序給予明確的預讀指示。
 
Linux 爲應用程序提供了三個預讀的系統調用: readahead(), posix_fadvise(), madvise()。其中 readahead() 是 Linux 特有的預讀 API,對於需要跨平臺的應用,不建議使用。它的功能等同於 posix_fadvise(POSIX_FADV_WILLNEED)。 posix_fadvise() 針對的是普通文件,它的參數和功能見表2.2; madvise() 針對的是mmap 文件,見表2.3。
這些預讀 API 大體上可以分爲兩類。一類是告知內核預期的訪問模式: NORMAL,SEQUENTIAL,RANDOM,NOREUSE,它們可以影響內核預讀算法的參數和行爲,使之進行更有針對性的預讀。另一類是直接進行緩存頁面的加載 ( WILLNEED) 和( DONTNEED) 操作,它們允許應用程序自己主導預讀和緩存。例如當 MySQL 數據庫管理系統即將訪問一些非連續分佈的表項,如果它確切地知道相關頁面的地址,就可以利用 posix_fadvise(POSIX_FADV_WILLNEED) 先行展開預讀。

高速緩存

分爲buffer cache和page cache的意義?
Buffer cache是包含磁盤塊數據的內存。
Page cache是磁盤緩存,專門用來存儲頁面幀,這些幀包含屬於普通文件的數據。

緩衝區高速緩存

使用目的:用於磁盤塊;緩衝區高速緩存用來將通過VFS訪問的塊的內容保留在內存中。
該部分比較複雜;需要多看幾遍;

頁高速緩存

使用目的:用於在磁盤上有文件映象的頁;頁高速緩存用來存放訪問磁盤文件內容時生成的磁盤數據頁;
這個部分相對於緩衝區高速緩存較爲簡單;
Read、write和mmap操作都是針對頁高速緩存完成的,信息單元是整頁,因爲頁IO操作要傳輸整頁數據;頁未必包含物理上相鄰的磁盤塊,因此不能用設備號和塊號來標識頁;相反,頁高速緩存中的一個頁的標識是通過文件的索引節點和文件的偏移量標識的;
由於頁高速緩存的緩存作用,寫操作實際上會被延遲。當頁告訴緩存中的數據比後臺存儲的數據更新時,那麼該數據就被稱作髒數據。在內存中累積起來的髒頁最終必須被寫回磁盤。在以下兩種情況發生時,髒頁被寫回磁盤:
(1)當空閒內存低於一個特定的閥值時,內核必須將髒頁寫回磁盤,以便釋放內存。
(2)當髒頁在內存中駐留時間超過一個特定的閥值時,內核必須將超時的髒頁寫回磁盤,以確保髒頁不會無限期的駐留在內存中。
   首先,pdflush線程在系統中的空閒內存低於一個特定的閥值時,將髒頁刷新回磁盤。特定的內存閥值可以通過drity_background_ratio sysctl系統調用設置。
   其次,pdflush後臺例程會被週期性喚醒,將那些在內存中駐留時間過長的髒頁寫出,確保內存中不會有長期存在的髒頁。系統管理員可以在/proc/sys/vm中設置回寫的相關參數,也可以通過sysctl系統調用來設置他們。


LINUX的虛擬內存實現

地址映射機制 VA到PA
內存的分配與回收
請頁機制
交換機制:page in (換入)和page out(換出)
內存共享機制
由於幾乎每次對虛擬內存中的頁面訪問都必須先解析它,從而得到物理內存中的對應地址,所以頁面操作的性能非常關鍵。但不幸的是,搜索內存中的物理地址速度 很有限,因此爲了加快搜索,多數體系結構都實現了一個翻譯後緩衝器(translation   lookaside buffer, TLB)。TLB作爲一個將虛擬地址映射到物理地址的硬件緩存,當請求訪問一個虛擬地址時,處理器將首先檢查TLB中是否緩存了該虛擬地址到物理地址的映 射,若在緩存中直接命中,物理地址立刻返回。

交換分區swap partion

Linux 中的 交換空間(Swap space) 在物理內存(RAM)被充滿時被使用。如果系統需要更多的內存資源,而物理內存已經充滿,內存中不活躍的頁就會被移到交換空間去。雖然交換空間可以爲帶有少量內存的機器提供幫助,但是這種方法不應該被當做是對內存的取代。交換空間位於硬盤驅動器上,它比進入物理內存要慢。
交換空間可以是一個專用的交換分區(推薦的方法),交換文件,或兩者的組合。

Linux: 查看swap分區信息

swapon –s

點擊打開鏈接
使用磁盤分區作爲swap
mkswap -f /dev/hda6
swapon /dev/hda6

使用文件作爲swap交換空間
dd if=/dev/zero of=/root/swapfile bs=1024 count=131072
mkswap –f /root/swapfile
swapon /root/swapfile


查看進程的虛擬內存
pmap PID

系統中可分配的內存總量= 物理內存的大小+ 交換設備的大小
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章