空間配置器詳解

引言

空間配置器,顧名思義就是爲各個容器高效的管理空間(空間的申請與回收)的,在默默地工作。

爲什麼需要空間配置器

自己模擬實現 STL 的容器的時候,如果所有空間都用 new 來申請,雖然可以使用但是會導致以下缺陷:
1)空間申請與釋放需要用戶自己管理,容易造成內存泄漏

2)頻繁向系統申請小塊內存塊,容易造成內存碎片
在這裏插入圖片描述
3)頻繁向系統申請小塊內存,影響程序運行效率

4)直接使用 malloc 與 new 進行申請,每塊空間前有額外空間浪費
頻繁申請小的內存塊,同樣需要管理,在空閒空間鏈表中找到分配空閒空間並且在空間頭部會記錄鏈表節點信息(prev next size)等等,這些信息也會佔據內存,相當於都浪費了,然而這些信息空間可能比申請的內存都大

SGI-STL空間配置器實現原理

以上的缺陷主要就是由頻繁申請小塊內存造成的,那麼我們需要先知道什麼纔是小塊內存,SGI-STL 中以 128 個字節來區分小塊和大塊內存,將空間配置器分爲兩級結構,一級空間配置器處理大塊內存,二級空間配置器處理小塊內存

一級空間配置器
一級空間配置器的原理就是直接將 malloc 和 free 進行了封裝,malloc 申請空間成功直接返回,申請失敗交給 oom_malloc 處理(檢查用戶是否設置了申請空間失敗的應對措施,如果沒有就拋異常,如果有就執行應對措施,然後重新申請)

二級空間配置器
二級空間配置器專門負責處理小於 128 字節的小塊內存。SGI-STL 採用了內存池的技術來提高申請空間的速度以及減少額外空間的浪費,採用哈希桶的方式來提高用戶獲取空間的速度

內存池
內存池就是:先申請一塊比較大的內存塊做備用,當需要內存時,直接到內存池中去取,當池中空間不夠時,再到內存中去取,當用戶不用時,直接還回內存池即可

SGI-STL中二級空間配置器設計
SGI-STL中的二級空間配置器使用了內存池技術,但沒有采用鏈表的方式對用戶已經歸還的空間進行管理(因爲在鏈表中查找空閒空間需要循環查找,效率低)而是採用了哈希桶的方式進行管理。
並且我們並不需要 128 個桶,因爲用戶申請的內存基本都是 4 的整數倍,乾脆將用戶申請的空間向上對齊,SGI-STL 才取得是向上對齊到 8 的整數倍(桶中的內存塊需要記錄自己內存地址,64位操作系統下一個指針爲8個字節,每個桶中的鏈的節點至少有一個指針也就是8個字節)

在這裏插入圖片描述

SGI-STL二級空間配置器之空間申請

申請空間:
所需字節數大於128由一級空間配置器來處理,不大於由二級空間配置器處理
先找到對應的桶,檢查桶下是否存在內存塊,存在直接將第一個內存塊返回給用戶
不存在要先向桶中添加內存塊(見下文),然後將第一個內存塊返回給用戶
在這裏插入圖片描述

填充內存塊:
會一次性向內存池索取20個內存塊,真實返回的內存塊不小於1
只有一塊就直接返回給用戶,否則將第一塊返回給用戶,剩餘的掛在對應的桶中
在這裏插入圖片描述
向內存池索要空間:
第一步:計算20個內存塊總大小和內存池剩餘空間大小,能提供20塊切割空間返回
第二步:不能提供20塊,能否提供至少一塊,能提供切割空間返回
第三步:一塊也不能提供,說明內存池空間不足,此時將內存池剩餘空間掛到對應桶下,通過系統堆第四步:補充內存池,補充成功則重新回到第一步
第五步:補充失敗,從哈希桶中找更大的內存塊補充,補充成功重新回到第一步
第六步:哈希桶也補充失敗,向一級空間配置器申請補充
在這裏插入圖片描述

SGI-STL二級空間配置器之空間回收
大於128字節交給一級空間配置器來釋放空間,否則將內存放入對應的哈希桶中,並不算真正的釋放直到程序結束纔會真正的釋放掉
在這裏插入圖片描述

空間配置器的默認選擇
SGI-STL默認使用二級空間配置器,通過USE_MALLOC宏進行控制,根據宏有無定義確定默認使用一級空間配置器還是二級空間配置器

缺陷
解決了外部內存碎片化,但是在哈希表中的內存依舊是碎片化的
直到進程退出纔會最終釋放資源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章