slab 分配機制。
slab 快取
linux 所使用的 slab 分配器的基礎是 jeff bonwick 為 sunos 作業系統首次引入的一種演算法。jeff 的分配器是圍繞
物件快取進行的。在核心中,會為有限的
物件集(例如
檔案描述符
和其他常見結構
)分配大量記憶體。jeff 發現對核心中普通物件
進行初始化
所需的時間超過了對其進行分配和釋放所需的時間。因此他的結論是不應該將記憶體釋放回乙個全域性的記憶體池,而是將記憶體保持為針對特定目而初始化的狀態。例如,如果記憶體被分配給了乙個互斥鎖,那麼只需在為互斥鎖首次分配記憶體時執行一次互斥鎖初始化函式(mutex_init)即可。後續的記憶體分配不需要執行這個初始化函式,因為從上次釋放和呼叫析構之後,它已經處於所需的狀態中了。
linux slab 分配器使用了這種思想和其他一些思想來構建乙個在空間和時間上都具有高效性的記憶體分配器。
圖 1 給出了 slab 結構的高層組織結構。在最高層是 cache_chain,這是乙個 slab 快取的鏈結列表。這對於 best-fit 演算法非常有用,可以用來查詢最適合所需要的分配大小的快取(遍歷列表)。cache_chain 的每個元素都是乙個 kmem_cache 結構的引用(稱為乙個cache)。它定義了乙個要管理的給定大小的物件池。
圖 1. slab 分配器的主要結構
每個快取都包含了乙個slabs列表,這是一段連續的記憶體塊(通常都是頁面)。存在 3 種 slab:
slabs_full
完全分配的 slab
slabs_partial
部分分配的 slab
slabs_empty
空 slab,或者沒有物件被分配
注意 slabs_empty 列表中的 slab 是進行**(reaping)
的主要備選物件。正是通過此過程,slab 所使用的記憶體被返回給作業系統供其他使用者使用。
slab 列表中的每個 slab 都是乙個連續的記憶體塊(乙個或多個連續頁),它們被劃分成乙個個物件。這些物件是從特定快取中進行分配和釋放的基本元素。注意 slab
是 slab 分配器進行操作的最小分配單位,因此如果需要對 slab 進行擴充套件,這也就是所擴充套件的最小值。通常來說,每個 slab 被分配為多個物件。
由於物件是從 slab 中進行分配和釋放的,因此單個 slab 可以
在 slab 列表之間
進行移動。例如,當乙個 slab 中的所有物件都被使用完時,就從 slabs_partial 列表中移動到
slabs_full
列表中。當乙個 slab 完全被分配並且有物件被釋放後,就從 slabs_full 列表中移動到 slabs_partial 列表中。當所有物件都被釋放之後,就從 slabs_partial 列表移動到 slabs_empty 列表中。
slab 背後的動機
與傳統的記憶體管理模式相比, slab 快取分配器提供了很多優點。首先,核心通常依賴於對
小物件的分配,它們會在系統生命週期內進行無數次分配。slab 快取分配器通過對
類似大小
的物件進行快取而提供這種功能,從而避免了常見的碎片問題。slab 分配器
還支援通用物件的初始化
,從而避免了為同一目的而對乙個物件重複進行初始化。最後,slab 分配器還可以支援硬體快取對齊和著色,這允許不同快取中的物件占用相同的快取行,從而提高快取的利用率並獲得更好的效能。
linux
中引入slab
的主要目的是為了
減少對夥伴演算法的呼叫次數。
實際上,核心經常反覆使用某一記憶體區。例如,只要核心建立乙個新的程序,就要為該程序相關的資料結構(task_struct、開啟檔案物件等)分配記憶體區。當程序結束時,收回這些記憶體區。因為程序的建立和撤銷非常頻繁,因此,linux的早期版本把大量的時間花費在反覆分配或**這些記憶體區上。從linux2.2開始,把那些
頻繁使用的
頁面儲存在快取記憶體中
並重新使用。
可以根據對記憶體區的使用頻率來對它分類。對於預期
頻繁使用的
記憶體區,可以建立一組特定大小的
專用緩衝區進行處理,以避免內碎片的產生。對於較少使用的
記憶體區,可以建立一組
通用緩衝區(如
linux2.0
中所使用的
2的冪次方)來處理,即使這種處理模式產生碎片,也對整個系統的效能影響不大。
硬體快取記憶體的使用,又為儘量減少對夥伴演算法的呼叫提供了另乙個理由,因為對夥伴演算法的每次呼叫都會「弄髒」硬體快取記憶體,因此,這就增加了對記憶體的平均訪問次數。
slab分配模式把物件分組放進緩衝區(儘管英文中使用了cache這個詞,但實際上指的是
記憶體中的
區域,而不是指硬體快取記憶體)。因為緩衝區的組織和管理與硬體快取記憶體的命中率密切相關,因此,slab
緩衝區並非由各個物件直接構成,而
是由一連串的「大塊(
slab
)」構成
,而每個大塊中則包含了若干個
同種型別
的物件,這些物件或已被分配,或空閒,如圖6.12所示。一般而言,物件分兩種,一種是大物件,一種是小物件。所謂小物件,是指在乙個頁面中可以容納下好幾個物件的那種。例如,乙個inode結構大約佔300多個位元組,因此,乙個頁面中可以容納8個以上的inode結構,因此,inode結構就為小物件。linux核心中把
小於512
位元組的物件叫做小物件。
實際上,緩衝區就是主存中的一片區域,把這片區域劃分為多個塊,每塊就是乙個
slab
,每個slab
由乙個或多個頁面組成,每個
slab
中存放的就是物件。
因為slab分配模式的實現比較複雜,我們不準備對其進行詳細的分析,只對主要內容給予描述。
slab的資料結構
slab分配模式有兩個主要的資料結構,乙個是描述緩衝區的結構kmem_cache_t,乙個是描述
slab
的結構kmem_slab_t,下面對這兩個結構給予簡要討論:
(1)slab
slab是slab管理模式中最基本的結構。它由一組連續的物理頁面組成,物件就被順序放在這些頁面中。其資料結構在mm/slab.c中定義。
slab結構示意圖
這裡的鍊錶用來將前乙個slab和後乙個slab鏈結起來形成乙個雙向鍊錶,colouroff為該slab上著色區的大小,指標s_mem指向物件區的起點,inuse是slab中所分配物件的個數。最後,free的值指明了空閒物件鏈中的第乙個物件,kmem_bufctl_t其實是乙個整數。
對於小物件,就把slab的描述結構slab_t放在該slab中;對於大物件,則把slab結構游離出來,集中存放。關於slab中的著色區再給予具體描述:
每個slab的首部都有乙個小小的區域是不用的,稱為「著色區(coloring area)」。著色區的大小使
slab
中的每個物件的起始位址
都按快取記憶體中的「快取行(
cache line
)」大小進行對齊(80386的一級快取記憶體行大小為16位元組,pentium為32位元組)。因為slab是由1個頁面或多個頁面(最多為32)組成,因此,每個
slab
都是從乙個
頁面邊界
開始的,它自然按快取記憶體的緩衝行對齊。但是,slab
中的物件大小不確定,設定著色區的
目的就是
將slab
中第乙個物件的起始位址往後推到
與緩衝行對齊
的位置。因為乙個緩衝區中有多個slab,因此,應該把每個緩衝區中的各個slab著色區的大小盡量安排成不同的大小,這樣可以使得在不同的
slab
中,處於同一相對位置的物件,讓它們在快取記憶體中的
起始位址相互錯開
,這樣就可以
改善快取記憶體的訪問效率。每個
slab
上最後乙個物件以後也有個小小的
廢料區是不用的,這是對著色區大小的補償,其大小取決於著色區的大小,以及slab與其每個物件的相對大小。但該區域與著色區的
總和對於同一種物件的各個
slab
是個常數。
每個物件的大小基本上是所需資料結構的大小。只有當資料結構的大小不與快取記憶體中的緩衝行對齊時,才增加若干位元組使其對齊
。所以,乙個
slab
上的所有物件的起始位址都必然是按快取記憶體中的緩衝行對齊的。
linux記憶體管理 之 slab分配器
1 頁面分配器是頁面級的記憶體分配工具,能分配2的order次冪的連續物理記憶體。linux在頁面級記憶體分配的基礎上,開發了小記憶體分配方案 slab slob slub。後兩者分別針對大型系統和嵌入式系統。2 slab分配器的思想 先利用頁面分配器分配出單個或者一組連續的物理頁面,然後在此基礎上...
Linux記憶體管理之slab分配器分析
一 準備知識 前面我們分析過了大記憶體分配的實現機制,事實上,若為小塊記憶體而請求整個頁面,這樣對於記憶體來說是一種極度的浪費。因此linux 採用了slab 來管理小塊記憶體的分配與釋放。slab 最早是由sun 的工程師提出。它的提出是基於以下因素考慮的 1 核心函式經常傾向於反覆請求相同的資料...
Linux記憶體管理slab分配器
在solaris 2.4以前,linux核心採用基於夥伴演算法實現的分割槽頁框分配器適合大塊記憶體的請求。夥伴將空閒頁面分為m個組,第1組儲存2 0個單位的記憶體塊,第2組儲存2 1個單位的記憶體塊,第3組儲存2 2個單位的記憶體塊,第4組儲存2 3個單位的記憶體塊,以此類推.直到m組.但是夥伴演算...