自訂記憶體配置器

slab 配置器(SLUB)

/ slab /

假設你的廚房不斷需要一模一樣、已擺好的餐桌:鋪好桌布、排好刀叉、放好玻璃杯。每一次都把桌子拆掉再從頭擺起,很浪費。更聰明的做法:保有一疊已經擺好的桌子,需要時發一張出去,回收時不要把它拆光——就讓它維持擺好的狀態,隨時能再用。slab 配置器對核心物件就是這麼做:它從快取(cache)中配置固定大小的物件,並記住它們已初始化的狀態,讓重用能省下擺設成本。

具體地說,slab 配置器(由 Jeff Bonwick 為 Solaris 發明,也是 Linux 核心配置器的範本)建立在兩個想法上。第一,物件快取(object cache):對每一種常用的物件——比如 struct inode 或 struct task_struct——都有一個專屬快取,發出剛好那個大小的物件。快取內部擁有一個或多個 slab,而一個 slab 是一塊連續的記憶體(通常是一頁或幾頁)切成許多相同大小的物件槽位,以 pool 的方式管理。第二,建構子重用/物件快取:當物件被釋放回快取時,配置器並不銷毀它;它可以讓物件維持部分初始化的狀態,使下一次配置對沒有改變的部分跳過重跑建構子(經典例子是物件內已初始化好的一個鎖或串列頭)。這讓常見核心物件的配置與初始化都非常便宜,並讓同型別物件緊密相鄰以利快取行為。

在 Linux 中,原本的 SLAB 大致已被 SLUB 取代——後者是同一 slab 概念的較簡單、較低開銷的重新實作,也是今日的預設(曾有一個低記憶體變體 SLOB,現已移除)。誠實的定位:slab 配置是核心內部大量使用、針對每種物件型別的特化層;它疊在以頁為粒度的 buddy 配置器之上,由後者供給 slab 系統原始的頁。所以 slab 解決的是大量小型固定大小核心物件的快速、無碎片配置,而底下的 buddy system 解決的是粗粒度、頁大小的配置。

/* Linux 核心:一種物件型別的快取,重用已初始化狀態 */ struct kmem_cache *c = kmem_cache_create("my_inode", sizeof(struct my_inode), 0, 0, my_ctor); /* ctor 每個槽位只跑一次 */ struct my_inode *p = kmem_cache_alloc(c, GFP_KERNEL); /* ... 使用 p ... 內嵌的鎖已由 ctor 預先初始化 */ kmem_cache_free(c, p); /* 還回快取,而非拆除 */

slab 快取發出同型別物件並重用其已初始化狀態,使重用能跳過重新建構。

slab 是核心側的特化,並非 malloc() 的直接替代品。它假設你會配置許多某種已知型別的物件,並仰賴底下以頁為單位的 buddy 配置器提供後備記憶體。

又稱
slab allocatorSLABSLUBobject cachekernel slab物件快取核心 slab