記憶體碎片(內部與外部碎片)
想像一排長書架,書一次又一次地被放上去、拿下來。過一陣子到處都是空隙——書架上的空位總量很多,但沒有任何一個空隙寬到能放下你想加入的那本大書。空間是有的,只是被打散了。記憶體碎片就是這件事的堆積版:可用的記憶體被打成太小或太分散的片段,無法滿足你實際提出的請求。
它有兩種風味。外部碎片就是書架空隙那幅畫面:閒置記憶體總量是有的,卻被切成許多不相鄰的小區塊,於是即使閒置空間總和足夠,一個大請求仍會失敗。它在一長串混合大小的配置與釋放後累積,因為不同大小的已釋放區塊留下一片拼布般的空洞。內部碎片則不同:它是你拿到的區塊內部被浪費的空間。配置器通常會把你的請求向上取整——為了滿足對齊,或因為它只管理某些尺寸級別的區塊——所以要求 33 個位元組可能給你一塊 48 位元組的區塊,那多出的 15 個位元組為你保留卻無法使用。它們不是永遠消失(釋放時你會拿回來),但在區塊存活期間算作額外開銷。
它的代價:外部碎片可能讓程式配置失敗,或迫使配置器向作業系統要更多記憶體,儘管它技術上握有足夠的閒置位元組;內部碎片則讓程式的記憶體用量膨脹到超過它實際儲存的資料。配置器以合併相鄰閒置區塊成更大區塊、以及選擇適配策略來反擊,但沒有任何通用配置器能完全消除碎片。當程式以非常規律的模式配置與釋放時,記憶體池或 arena 配置器能以相同方式處理所有區塊,從而繞過碎片問題。
閒置 8 + 閒置 8 + 閒置 8 = 共 24 位元組閒置,但分成三個獨立空隙。 請求 16 個連續位元組可能失敗 -> 外部碎片。 要求 33 個位元組,拿到一塊 48 位元組區塊:浪費 15 個位元組 -> 內部碎片。
外部:閒置總量足夠但沒有單一夠大的空隙。內部:已授予區塊內部被浪費的填充。
閒置位元組總量可能超過一個仍然失敗的請求——那就是外部碎片,也是為什麼一個沒有洩漏的程式仍可能耗盡可用記憶體。