first-fit/best-fit/next-fit 放置策略
假設你經營一座停車場,裡面有各種寬度的空位,來了一輛車需要停。你要把它停進哪個空位?你可以挑你找到的第一個夠寬的空位(快,但也許草率)。你可以巡視整座停車場,挑最貼合的空位,留下最少的剩餘(整齊,但決定起來慢)。或者你可以記住上一輛車停在哪裡,從那裡開始找。這正是配置器用來選擇從哪個空閒區塊滿足請求的放置策略。
把三個經典策略在自由串列上走一遍:first-fit(首次適配)從串列開頭掃描,抓住第一個夠大的區塊——快、簡單,但它傾向啃掉串列前段的區塊,可能在那裡留下一堆小剩餘。best-fit(最佳適配)掃描整條串列,選擇仍然夠大的最小區塊,使切割後剩下的碎片盡可能小——這能把記憶體塞得很緊、對抗外部碎片,但它必須檢視每一個空閒區塊(慢),且可能產生許多微小、無用的剩餘。next-fit(下次適配)是帶記憶的 first-fit:它從上一次搜尋停下的地方接續掃描,而非總是從前頭開始,這會把配置分散到堆積各處、避免重走擁擠的前段——通常比 first-fit 快,但碎片往往略差。(worst-fit,選最大的區塊,也存在,其理論是剩餘仍夠大可重用,但它的表現往往不好。)
為何重要:放置策略是配置器的核心決策,直接形塑碎片與速度的權衡。誠實且被廣泛研究的結論是沒有通用贏家——最佳策略取決於工作負載的大小與生命期模式;而且令人意外地,在良好資料結構上的單純 first-fit 或 next-fit,實務上往往表現得跟 best-fit 差不多,卻快得多。這正是為什麼現代配置器對小物件大致用 size class 與分離式串列繞過了這個問題——在分離式串列中,某類別內每個區塊都相同,根本沒有適配可選。
/* 自由串列大小: [ 80 ] [ 32 ] [ 200 ] [ 48 ] 請求:40 位元組 */ /* first-fit :選 80 (第一個 >= 40 的區塊) */ /* best-fit :選 48 (>= 40 的最小區塊,剩餘最少) */ /* next-fit :選上次搜尋點之後第一個 >= 40 的區塊 */
同一個請求、三種策略、選出三個不同的區塊——在搜尋時間與記憶體塞得多緊之間權衡。
best-fit 不一定最好:它讓每次配置的剩餘最小,但很慢,且可能把堆積撒滿無法使用的微小剩餘。沒有任何單一適配策略能在所有工作負載上勝出。