動態記憶體管理

配置中介資料(區塊標頭)

這裡有個小謎題。當你呼叫 free(p) 時,你只傳了指標——你從未告訴 free 那塊區塊有多大。然而 free 必須知道大小,才能把正確份量的記憶體還給自由串列、並檢查鄰居以便合併。它怎麼知道的?答案是配置器悄悄把大小與其他記帳資料存在你區塊的旁邊,存在一塊稱為區塊標頭(或中介資料)的小區域裡。

精確地說:當 malloc 給你一個指向可用位元組的指標時,它通常已在那個指標之前放了幾個隱藏的位元組——標頭——至少記錄該區塊的大小、它是閒置還是使用中,常常還有自由串列的連結。所以一筆配置的記憶體布局看起來是:標頭,然後是你實際使用的位元組。malloc 回傳的指標指向你的可用區域,就在標頭之後。當你呼叫 free(p) 時,配置器從 p 往回退一個標頭大小,讀取它在那裡找到的大小與旗標,並用它們來回收區塊。這就是為什麼你必須把 malloc 回傳的那個確切指標傳給 free:指向你區塊中間的指標會指向錯誤的地方,配置器就會在它期望有標頭的位置讀到垃圾。

這份中介資料有兩個值得記住的後果。第一,它是額外開銷:每筆配置都為它的標頭(與對齊填充)花一點額外記憶體,這就是為什麼做成千上萬筆微小的獨立配置,比起一大塊或一個記憶體池來得浪費。第二,標頭就坐在你可用位元組的緊鄰處,所以一個寫過你區塊尾端的緩衝區溢位,能覆寫下一塊的標頭、破壞配置器。這正是為什麼堆積溢位常在稍後、於 malloc 或 free 內部當機,而非在溢位的那一行——損害的是記帳資料,不是你自己的資料。

一筆配置的記憶體布局: [ 標頭:大小 + 閒置/使用旗標 ][ 你的可用位元組 -> p 指向這裡 ] free(p) 從 p 往回退去讀標頭,然後回收區塊。

大小住在你指標之前的隱藏標頭裡;這就是 free 不必被告知也能知道要回收多少的方法。

標頭解釋了為何你必須釋放 malloc 回傳的確切指標、為何溢位會破壞配置器、以及為何許多微小配置會在逐塊開銷上浪費記憶體。

又称
block headerallocation headerbookkeeping區塊標頭記帳資料