1. 程式人生 > >linux記憶體管理之全域性框架

linux記憶體管理之全域性框架

  講解複雜繁瑣的機制原理,最通俗的方法就是用模型架構的方式向讀者呈現,先要在整體上了解大方向大架構,再根據大方向大架構來進行分支深入,猶如毛主席那句話“戰略上蔑視敵人,戰術上重視敵人”。下面我也以這種方式把各個大模型方式向大家畫出,並作出簡略解述。

一.  地址劃分。

  1. CPU地址。

  CPU地址是指CPU的地址匯流排能定址的範圍,32bit-CPU定址範圍為4G, 這個地址是虛擬的,實際上外部實體記憶體是不會使用這麼大的記憶體。

  CPU虛擬地址的4G空間,通常劃分為兩部分,一部分為核心虛擬地址,通常為3G-4G之間,另一部分為使用者虛擬地址,通常為0G-3G之間,顯然,使用者程序能使用的虛擬地址範圍遠大於核心可以使用的虛擬地址空間,但是,實體記憶體只有侷限性的幾M,幾G,核心虛擬地址如何使用實體記憶體,使用者空間如何使用實體記憶體,這些問題正是linux記憶體管理的關鍵。

  2.  實體記憶體

  實體記憶體是指外部儲存資料的裝置,有可以被CPU定址到的地址匯流排,受到CPU的Cache 和TLB/MMU管理定址。

  需要澄清一個概念:任何程式碼是在CPU上執行的,而不是在實體記憶體上,實體記憶體是個裝置,用於存放使用者程序空間的可執行程式碼或者核心關鍵資料結構,這些程式碼或結構終將是要受到CPU通過MMU定址,Cache命中指令資料來獲取的。

  NUMA的全稱是非一致性記憶體訪問,它通常是多核訪問的概念,每一個CPU核都會有一個節點對應使用一部分實體記憶體,對這些節點的管理附加這些資料結構:perCPU變數,list表串聯各節點遍歷,zone的劃分,zonelist的管理等等。為了使問題更加簡單化,我們只分析UMA的一個節點的情況,當然它也包含NUMA的一些資料結構特徵,這個後面會有所簡述。

  下圖是NUMA的一個簡略圖抽象如圖2-1所示。

  

                                   圖2-1 NUMA多核實體記憶體zone示意圖

  3.  核心虛擬地址空間劃分。

  如果讀者僅僅瞭解一些皮毛,必然認為核心的虛擬地址空間僅有邏輯地址這一說,其實這只是記憶體核心虛擬地址劃分的一個特例,並非全部的完整表述,現在我劃出完整的圖形,並且改變改變對核心虛擬地址空間名稱的叫法,如圖2-2

                       圖2-2 核心虛擬地址空間劃分及其對實體記憶體的對映

  下面來改改名字咯,直接對映的地址我們可以叫為核心物理直接對映地址或者邏輯地址。linux原則上只能使用虛擬空間1G中的896M,剩下的128M留作它用,所以直接對映之外的實體記憶體稱為高階記憶體。128M之間的空間又劃分為多個gap安全間隙,虛擬地址,固定對映和持久對映,注意這裡的虛擬地址叫法通常和前述的核心虛擬地址有些混雜,後者是指CPU核心虛擬地址,是更廣的概念。由於直接對映的部分有了名字叫邏輯地址,那麼這裡的虛擬地址空間常專指這個部分。

  虛擬地址有以下用途,使用vm_struct結構體經核心管理高階記憶體,它可以使用kmap方式獲取高階實體記憶體的空間;也可以不對映物理高階記憶體,將這段地址直接作為外部物理裝置的ioremap地址,從而可以直接操縱裝置,當然這也將外部裝置地址空間暴露出來並且容易造成干擾,所以通常不能直接訪問ioremap對映的地址而是用readb/writeb讀寫,而且要做好優化屏障設定並且用iounmap釋放,因為映射了的裝置常具有’邊際效應’.

  如果沒有高階記憶體,(當然32bit的嵌入式系統通常不會使用高階記憶體,至少我見過的那麼多關於ARM,powerPC,MIPS32的嵌入式應用都是沒有使用高階記憶體的), 那麼固定對映和持久對映也多半不會用到。固定對映可以指定長期持有實體記憶體某些地址頁的佔用,這個對映關係可以在初始階段進行配置,而持久對映在啟用時就建立了同高端記憶體物理頁的對映關係,它在其他階段都不會被解除。

  強調的是,我這裡不關心高階記憶體,核心的直接對映邏輯地址就可以涵蓋全部實體記憶體。

  4.  使用者虛擬地址空間的劃分

  使用者虛擬地址空間圖構並不複雜,複雜的是它在虛擬記憶體空間中的應用,如何對映檔案,如何組織區間對映,關聯的程序是誰,對應的記憶體結構體例項是什麼等等問題才是使用者虛擬對映最難的地方,下面僅僅劃出圖示,對使用者虛擬記憶體空間可以先有一個大瞭解,如圖2-3。

        

                           圖2-3使用者空間虛擬記憶體佈局

   既然使用者空間是虛擬的,那麼它是怎麼訪問實體記憶體的呢,當然就是PGD,PUD,PMD,PTE,OFFSET及其TLB快表查詢了,上層目錄入口PUD和中間目錄入口一般不考慮,考慮二級目錄就可以了。從網上摘的圖2-4:

        

                            圖2-4 使用者程序空間訪問實體記憶體的方法

二.  夥伴系統

夥伴系統是按階管理外界實體記憶體的方法,最大有11階,每一階有一個或者多個頁合併的集合並使用指標串聯起來,同時在同一階中的一個或多個頁集合中形成各自的夥伴,要強調的是各個階的夥伴都是等頁個數的,用下圖2-5是比較好理解的。

        

                                        圖2-5 夥伴系統在記憶體中的大致模型

  當核心申請一段按頁卻並非按照階數分配的記憶體時候,通常會使用夥伴系統原理將其按照該申請空間的最大階數分配,多出來的頁按照夥伴系統演算法歸併到其他階的連結串列當中形成其他階的新夥伴。釋放該記憶體空間的時候,釋放的空間會嘗試找到能以它為夥伴的那個階進行連線,如果大小超過,則劈開,多餘的再尋找其他可以以它為夥伴的階。夠拗口的,但還是很容易理解的,後面會有原始碼呈現出來以例項詳細分析。

三.  反碎片技術:

  反碎片機制其實還在夥伴系統之前,它主要是將各個zone區域的實體記憶體分成可回收reclaimable但不可移動unmovable,可移動movable,不可移動unmovable. 這些標記按照一定得list串聯起來管理,當外部條件申請實體記憶體導致許多碎片的時候,它可以按照這些資料結構的標誌,來從新組織歸類實體記憶體,從而減少碎片頁或者孤獨頁。反碎片技術在嵌入式系統當中少用,絕大部分由夥伴系統佔據江山了,因此不會對此做具體分析,簡略過之。

四.    Slab分配機制。