堆積邊界(sbrk 與 mmap)
/ ES-bee-ar-kay /
當 malloc 的自由串列上沒有夠大的閒置區塊時,它得從某處取得更多記憶體。但 malloc 本身只是個函式庫函式——它並不擁有任何記憶體;只有作業系統擁有。所以 malloc 必須請求核心擴大程式的堆積。堆積邊界是標示堆積目前頂端的界線,把它向上推就是行程從作業系統取得更多原始記憶體的方式。
有兩個系統呼叫做這件事。較舊、較簡單的是 brk/sbrk:堆積被布置成一塊連續區域,從程式的資料段之後開始、向上成長,而程式邊界(program break)就是標示其目前尾端的位址。呼叫 sbrk(amount) 把那道邊界往上推 amount,一次給行程多那麼多位元組、成一整片連續的堆積。malloc 接著從這片厚板中切出使用者尺寸的區塊。第二種機制是 mmap,它向核心索取一塊不綁定於連續堆積的全新記憶體區域——現代配置器對大型請求使用 mmap,把該區域直接回傳給使用者,並在釋放時取消映射。無論哪種,關鍵想法是:malloc 從核心大批量地(透過 sbrk 或 mmap)批發記憶體,再零售小片給你的程式,把剩下的留在自由串列上。
這對身為初學者的你為何重要:它解釋了為什麼 malloc 與 free 通常很快,即使它們可能牽涉核心。大多數配置完全由配置器已取得的記憶體供應——根本不做系統呼叫——因為進入核心相對昂貴。配置器只在真正短缺時才呼叫 sbrk 或 mmap,並傾向保留記憶體而非急著歸還。這也是為什麼一個行程的記憶體占用常常成長卻很少縮小:即使你釋放了,配置器仍保留那片厚板以供未來請求。
malloc(40) -> 自由串列有合適者 -> 立即供應,無系統呼叫。 malloc(40) -> 自由串列為空 -> sbrk(132072) 一次擴大堆積, 然後這次與許多未來的小 malloc 都從那片厚板切出。
配置器透過 sbrk 或 mmap 向核心批發記憶體,再零售小區塊而不再做系統呼叫。
本條目只把 mmap 當作 malloc 取得記憶體的來源;mmap 作為分頁與檔案映射機制的角色,是虛擬記憶體領域中另一個更大的主題。