歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux slab 分配器剖析

Linux slab 分配器剖析

日期:2017/2/28 16:13:31   编辑:Linux教程

簡介: 良好的操作系統性能部分依賴於操作系統有效管理資源的能力。在過去,堆內存管理器是實際的規范,但是其性能會受到內存碎片和內存回收需求的影響。現在,Linux? 內核使用了源自於 Solaris 的一種方法,但是這種方法在嵌入式系統中已經使用了很長時間了,它是將內存作為對象按照大小進行分配。本文將探索 slab 分配器背後所采用的思想,並介紹這種方法提供的接口和用法。

動態內存管理

內存管理的目標是提供一種方法,為實現各種目的而在各個用戶之間實現內存共享。內存管理方法應該實現以下兩個功能:

  • 最小化管理內存所需的時間
  • 最大化用於一般應用的可用內存(最小化管理開銷)

內存管理實際上是一種關於權衡的零和游戲。您可以開發一種使用少量內存進行管理的算法,但是要花費更多時間來管理可用內存。也可以開發一個算法來有效地管理內存,但卻要使用更多的內存。最終,特定應用程序的需求將促使對這種權衡作出選擇。

每個內存管理器都使用了一種基於堆的分配策略。在這種方法中,大塊內存(稱為 )用來為用戶定義的目的提供內存。當用戶需要一塊內存時,就請求給自己分配一定大小的內存。堆管理器會查看可用內存的情況(使用特定算法)並返回一塊內存。搜索過程中使用的一些算法有 first-fit(在堆中搜索到的第一個滿足請求的內存塊)和 best-fit(使用堆中滿足請求的最合適的內存塊)。當用戶使用完內存後,就將內存返回給堆。

這種基於堆的分配策略的根本問題是碎片(fragmentation)。當內存塊被分配後,它們會以不同的順序在不同的時間返回。這樣會在堆中留下一些洞,需要花一些時間才能有效地管理空閒內存。這種算法通常具有較高的內存使用效率(分配需要的內存),但是卻需要花費更多時間來對堆進行管理。

另外一種方法稱為 buddy memory allocation,是一種更快的內存分配技術,它將內存劃分為 2 的冪次方個分區,並使用 best-fit 方法來分配內存請求。當用戶釋放內存時,就會檢查 buddy 塊,查看其相鄰的內存塊是否也已經被釋放。如果是的話,將合並內存塊以最小化內存碎片。這個算法的時間效率更高,但是由於使用 best-fit 方法的緣故,會產生內存浪費。

本文將著重介紹 Linux 內核的內存管理,尤其是 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 分配器還可以支持硬件緩存對齊和著色,這允許不同緩存中的對象占用相同的緩存行,從而提高緩存的利用率並獲得更好的性能。

Copyright © Linux教程網 All Rights Reserved