自訂記憶體配置器

size class(大小類別)

如果一家服飾店為每一個精確的身體尺寸都賣一件不同的衣服,倉庫會一團亂。店家改用尺碼——S、M、L、XL——並把每位顧客向上湊到最接近的一個。一件衣服也許穿起來稍微寬鬆,但存貨與處理變得簡單。size class(大小類別)對記憶體請求做的是同一件事:與其逐一服務每個精確的位元組數,配置器把每個請求向上湊到一組固定標準尺寸中的一個,並以這些尺寸來管理記憶體。

它是這樣被使用的。配置器定義一份排序好的 size class 清單——典型方案是小尺寸間距細密(8、16、24、32、48、64、80、96……),到較大尺寸時拉寬成大致幾何級數的步距(好讓浪費的比例保持有界)。一個比如 50 位元組的請求會被向上湊到下一個類別 64,配置器接著就只用 64 位元組的區塊來處理它:它為每個類別保有一條分離式自由串列,於是所有記帳(自由串列、slab、執行緒快取)都按類別組織。因為某個類別內每個區塊大小都相同,配置不需要適配搜尋——只要取下該類別的串列——而被釋放的區塊立刻可供任何同類別請求重用,所以類別內沒有外部碎片。

size class 是每個快速現代配置器的組織原則:jemalloc、tcmalloc、mimalloc 全都把配置切進 size class,再按類別分離、執行緒快取與回收。代價是內部碎片——你的請求與被湊進的類別之間的落差(50 變 64 時浪費的那 14 位元組)。配置器作者會調整類別表來平衡兩種惡:類別太少意味大量湊整浪費;太多則意味更多串列、更多中介資料、更差的快取區域性。其中的技藝是選擇類別邊界,使每區塊浪費保持很小(通常壓在 10-15% 上下),同時讓類別數量維持可控。

/* size class 表的一小段;把請求「向上」湊到某個類別 */ /* 類別:8, 16, 24, 32, 48, 64, 80, 96, 112, 128, ... */ size_t round_to_class(size_t n) { /* 50 -> 64(浪費 14 位元組的內部碎片) */ return next_class_ge(n); }

每個請求都被向上湊到一個標準類別大小;那個落差就是內部碎片,是快速分離式串列的代價。

湊到 size class 永遠是向上而非向下——你拿到的必須至少是你所要求的。間距越小,每區塊浪費越少,但要管理的串列與中介資料數量也成倍增加。

又稱
size bucketallocation classbin size大小桶尺寸級距