slab機制總結篇

FreeeLinux發表於2017-01-16

唔,花了一個星期看完了slab機制的原始碼,不愧是linux核心原始碼,和我當初看libevnt原始碼有一拼。兩者都是資料比較少,只有零散的部落格,沒有成文的書,因此加大了自己理解的難度。如果有書籍的話,那麼根本不需要一個星期。

下面要開始總結了。

一:

slab是為了解決內部碎片提出的,還是外部碎片?

為了解決內部碎片。

內部碎片的產生:因為所有的記憶體分配必須起始於可被 4、8 或 16 整除(視處理器體系結構而定)的地址或者因為MMU的分頁機制的限制,決定記憶體分配演算法僅能把預定大小的記憶體塊分配給客戶。假設當某個客戶請求一個 43 位元組的記憶體塊時,因為沒有適合大小的記憶體,所以它可能會獲得 44位元組、48位元組等稍大一點的位元組,因此由所需大小四捨五入而產生的多餘空間就叫內部碎片。

外部碎片的產生: 頻繁的分配與回收物理頁面會導致大量的、連續且小的頁面塊夾雜在已分配的頁面中間,就會產生外部碎片。假設有一塊一共有100個單位的連續空閒記憶體空間,範圍是0~99。如果你從中申請一塊記憶體,如10個單位,那麼申請出來的記憶體塊就為0~9區間。這時候你繼續申請一塊記憶體,比如說5個單位大,第二塊得到的記憶體塊就應該為10~14區間。如果你把第一塊記憶體塊釋放,然後再申請一塊大於10個單位的記憶體塊,比如說20個單位。因為剛被釋放的記憶體塊不能滿足新的請求,所以只能從15開始分配出20個單位的記憶體塊。現在整個記憶體空間的狀態是0~9空閒,10~14被佔用,15~24被佔用,25~99空閒。其中0~9就是一個記憶體碎片了。如果10~14一直被佔用,而以後申請的空間都大於10個單位,那麼0~9就永遠用不上了,變成外部碎片。

二:

slab演算法的核心思想是什麼?

slab的核心思想是以物件的觀點來管理記憶體。

核心對其物件的使用具有以下特殊性:

  1. 核心使用的物件種類繁多,應該採用一種統一的高效管理方法。
  2. 核心對某些物件(如 task_struct)的使用是非常頻繁的,所以使用者程式堆管理常用的基於搜尋的分配演算法比如First-Fit(在堆中搜尋到的第一個滿足請求的記憶體塊)和 Best-Fit(使用堆中滿足請求的最合適的記憶體塊)並不直接適用,而應該採用某種緩衝區的機制。
  3. 核心物件中相當一部分成員需要某些特殊的初始化(例如佇列頭部)而並非簡單地清成全 0。如果能充分重用已被釋放的物件使得下次分配時無需初始化,那麼可以提高核心的執行效率。
  4. 分配器對核心物件緩衝區的組織和管理必須充分考慮對硬體快取記憶體的影響。
  5. 隨著共享記憶體的多處理器系統的普及,多處理器同時分配某種型別物件的現象時常發生,因此分配器應該儘量避免處理器間同步的開銷,應採用某種 Lock-Free 的演算法。

所以,這就需要slab機制以物件的觀點來解決小記憶體問題。

三:有關slab的著色問題

著色與硬體cache有關,這就牽扯到cache和主存的工作結構:

  1. 全相連
    • 任一主存塊能對映到任意快取行(主存塊的大小等於快取行的大小。
    • 優點:靈活,不易產生衝突
    • 缺點:比較電路難於實現,且效率低,速度慢
  2. 直接對映
    • 某一主存塊只能對映到特定的快取行
    • 優點:硬體簡單,成本低
    • 缺點:容易產生衝突,易產生快取“顛簸”,不能有效利用cache空間
  3. 組相聯
    • 組間直接對映,組內全相聯對映
    • 優點:結合上面兩種的優點
      • 因為組內行數較少,比較器容易實現
      • 組內又有靈活性,衝突大大減小

由上可知,slab著色對於直接對映和組相連對映的工作結構效率幫助較大,而全項鍊結構本身衝突就比較小,那麼著色的幫助是很小的。在全相連工作結構中,使用著色無疑是一個巨大的記憶體浪費。

slab演算法的缺點

隨著大規模多處理器系統和NUMA系統的廣泛應用,slab分配器逐漸暴露出自身嚴重的不足:

  1. 較多複雜的佇列管理。在slab分配器中存在眾多的佇列,例如針對處理器的本地快取佇列,slab中空閒佇列,每個slab處於一個特定狀態的佇列之中。所以,管理太費勁了。
  2. slab管理資料和佇列的儲存開銷比較大。每個slab需要一個struct slab資料結構和一個管理者kmem_bufctl_t型的陣列。當物件體積較小時,該陣列將造成較大的開銷(比如物件大小為32位元組時,將浪費1/8空間)。為了使得物件在硬體告訴快取中對齊和使用著色策略,還必須浪費額外的記憶體。同時,緩衝區針對節點和處理器的佇列也會浪費不少記憶體。測試表明在一個1000節點/處理器的大規模NUMA系統中,數GB記憶體被用來維護佇列和物件引用。
  3. 緩衝區回收比較複雜。
  4. 對NUMA的支援非常複雜。slab對NUMA的支援基於物理頁框分配器,無法細粒度的使用物件,因此不能保證處理器級的快取來自同一節點(這個我暫時不太懂)。
  5. 冗餘的partial佇列。slab分配器針對每個節點都有一個partial佇列,隨著時間流逝,將有大量的partial slab產生,不利於記憶體的合理使用。
  6. 效能調優比較困難。針對每個slab可以調整的引數比較複雜,而且分配處理器本地快取時,不得不使用自旋鎖。
  7. 除錯功能比較難於使用。

為了解決以上slab分配器的不足,引入新的解決方案,slub分配器。slub分配器的特點是簡化設計理念,同時保留slab分配器的基本思想:每個緩衝區有多個slab組成,每個slab包含固定數目的物件。slub分配器簡化了kmem_cache,slab等相關的管理結構,擯棄了slab分配器中的眾多佇列概念,並針對多處理器、NUMA系統進行優化,從而提高了效能和可擴充套件性並降低了記憶體的浪費。並且,為了保證核心其他模組能無縫遷移到slub分配器,API介面函式與slab保持一致。

缺點簡單說就是:

  1. 快取佇列管理複雜;
  2. 管理資料儲存開銷大;
  3. 對NUMA支援複雜;
  4. 除錯調優困難;
  5. 摒棄了效果不太明顯的slab著色機制;

過些天就開始剖析slub分配器,不過由於有slab的基礎,那個已經是小菜了。

參考:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3559586&extra=&authorid=16801415&page=1

相關文章