乙個簡單的記憶體分配器 《深入理解計算機作業系統》

2022-03-09 22:48:26 字數 1286 閱讀 7912

我相信很多人都知道《深入理解計算機作業系統》這本書,並且很多人都會對它研讀。實際本人剛開始看的時候,只是加深了對作業系統的理解,別的到是沒有感覺的到,

但是在看到公司的軟體框架裡面對於記憶體堆的管理,才發現和書上講的異曲同工。於是乎,自己對利用隱式的空閒鍊錶實現分配器做了總結,並且和自己想到的架構做了對比分析。

我們知道乙個實際的分配器,不僅要考慮好吞吐率和記憶體利用率之間的平衡,還要考慮:

①空閒塊組織:我們如何記錄空閒塊(一般剛開始會把一整段堆當做空閒塊,然後再分割)

②放置:我們如何選擇乙個合適的空閒塊來放置乙個新分配的塊?

③分割:在乙個空閒塊裡面放置乙個塊後,剩餘的空閒部分怎麼處理?

④合併:我們如何處理剛剛釋放的塊?假如有兩個塊都是空閒的,需要合併嗎 ?

管理:於是書中定義乙個資料結構來區分塊邊界,用來記錄空閒塊,這個資料結構是:

塊大小包括頭、有效負荷和填充部分,這樣就可以記錄出空閒和以分配的塊,對應的隱式空閒鍊錶如下圖所示:

放置和分割:假如我們想要放置已經分配塊時,分配器會搜尋鍊錶,尋求乙個足夠大的空閒塊來放置,有首次放配的策略、下一次分配的策略和最佳適配的策略,為了方便起見,我們將使用首次分配,從堆頭開始搜尋空閒鍊錶,選擇第乙個合適的空閒塊,這樣的優點是趨向於將大的空閒塊放在最後,缺點是開始的地方有小空閒塊的「碎片」。當你找到乙個匹配的空閒塊時,你要做決定是否需要分割,這樣的話第一部分變成分配塊,而剩下的部分還為空閒塊,如下圖所示:

合併:合併的問題最需要考慮的,當分配器釋放乙個分配塊時,假如其他的空閒塊於之相連,這個時候需要合併,我們假設是立即合併(實際快速的分配器不會是立即合併,會選擇推遲合併)。如果是下乙個塊時空閒塊,可以讓釋放掉的空閒塊的頭部,加上塊大小,指向下乙個塊,然後讀出下乙個塊的大小,就將它的大小簡單的加到當前塊頭部的大小上。但是如果是前面的塊時空閒塊的話,就需要搜尋整個鍊錶,記錄前面的塊再進行合併,這樣free需要的時間與堆的大小成線性關係,對於吞吐率是有很大的影響,這個時候knuth記錄提出了邊界標記(boundary tag),在腳部新增乙個頭部的副本,這個腳部總是在距當前塊開始位置乙個字的距離。實際這樣是犧牲了記憶體來實現吞吐率的。

當然了,為了我們結構的可讀性更好,我們可以定義乙個頭部結構體,不用放腳部標記了

typedef struct

size_t sec_size;//塊的大小,用於比較和申請記憶體的塊,找到能放的下的空閒塊(在已經分配的塊上,這個值一般等於alloc_size)

size alloc_size;//有效負載的大小,由於知道結構體的大小,相當於上文中知道了塊大小

如何設計乙個記憶體分配器

通常工程裡不推薦自己寫記憶體分配器,因為你費力寫乙個出來99 可能性沒有內建的好,且記憶體出bug難除錯 不過看書之餘,你也可以動手自己試試,當個玩具寫寫玩玩 1.實現教科書上的記憶體分配器 做乙個鍊錶指向空閒記憶體,分配就是取出一塊來,改寫鍊錶,返回,釋放就是放回到鍊錶裡面,並做好歸併。注意做好標...

STL中的記憶體分配器 (一)

題記 記憶體管理一直是c c 程式的 關於記憶體管理的話題,大致有兩類側重點,一類是記憶體的正確使用,例如c 中new和delete應該成對出現,用raii技巧管理記憶體資源,auto ptr等方面,很多c c 書籍中都使用技巧的介紹。另一類是記憶體管理的實現,如linux核心的slab分配器,st...

夥伴分配器的乙個極簡實現

提起buddy system相信很多人不會陌生,它是一種經典的記憶體分配演算法,大名鼎鼎的linux底層的記憶體管理用的就是它。這裡不 核心這麼複雜實現,而僅僅是將該演算法抽象提取出來,同時給出乙份及其簡潔的原始碼實現,以便定製擴充套件。夥伴分配的實質就是一種特殊的 分離適配 即將記憶體按2的冪進行...