面試淺談 c++ 的空間兩級配置器

最近面試c++的時候,被問到c++內存管理模型,沒用過。回來看了下《STL源碼解析》,這裏簡單總結下,不涉及具體實現。感興趣同學可以下載電子書自己看下。

SGI版本的空間適配器設計哲學:

  1. 向system heap 要求空間。
  2. 考慮多線程狀態。
  3. 考慮內存不足時的應變措施。
  4. 考慮過多“小型區塊”可能造成的內存碎片(fragment)問題。

考慮到小型區塊可能造成的內存碎片問題,SGI設計了雙層級配置器,第一級配置器直接使用malloc()和free(),第二級配置器則視情況採用不用的策略:當配置區塊超過128字節時,視之爲"足夠大",便調用第一級配置器;當配置區塊小於128字節時,視之爲“過小”,爲了降低額外負擔,便採用複雜的內存池整理方式,而不再求助於第一級配置器。

一、二級配置器的關係,接口包裝如下圖:

第一級配置器以malloc(), free(), realloc()等C函數執行實際的內存配置、釋放、重配置操作。

第二級配置器多了一些機制,避免太多小額區塊造成內存的碎片。小額區塊帶來的其實不僅是內存碎片,配置時的額外負擔也是一個大問題。額外負擔永遠無法避免,但是區塊愈小,額外負擔所佔的比例就愈大,愈顯得浪費。這裏的額外負擔指的是分配的內存需要一段信息保存內存的大小、下一個節點指針等額外信息。

SGI第二級配置器的做法是,如果區塊夠大,超過128字節時,就移交第一級配置器處理。當區塊小於128字節時,則以內存池管理,此法又稱爲次層配置:每次配置一大塊內存,並維護對應之自由鏈表(free-list)。下次若再有相同大小的內存需求,就直接從free-lists中拔出。如果客戶端釋放小額區塊,就由配置器回收到free-lists中。爲了方便管理,SGI第二級配置器會主動將任何小額區塊的內存需求量上調至8的倍數,並維護16個free-lists,各自管理大小爲8,16,24,32....128的小額區塊。邏輯圖如下:

分配內存首先判斷區塊大小,大於128字節就直接調用第一級配置器,小於128字節就檢查對應的自由鏈表free-lists。如果自由鏈表中有可用的區塊,就直接拿來使用,如果沒有可用區塊,則需要重新填充空間。釋放的時候,首先判斷區塊大小,大於128字節就調用第一級配置器,小於128就找出對應的自由鏈表,將區塊回收。

當發現自由鏈表中沒有可用區塊了時,需要爲自由鏈表重新填充空間。新的空間將取自內存池。缺省取得20個新節點,但萬一內存池空間不足,獲得節點數可能小於20。內存池如果水量充足,則直接分配20個區塊給free-list 。如果水量不足20個,但超過1個以上,就撥出這不足20個區塊的空間出去。如果內存池連一個區塊空間都無法供應,此時需要利用malloc()從heap中配置內存,爲內存池注入活水以應付需求。新水量的大小爲需求量的兩倍,再加上一個隨着配置次數增加而愈來愈大的附加量。

萬一山窮水盡,整個system heap空間不夠了,malloc行動失敗,則四處查找有無“尚有未用區塊,且區塊夠大”的free list,找到了就挖一塊,找不到就調用第一級配置器。第一級配置器其實也是使用malloc來配置內存,但它有out-of-memory處理機制,或許有機會釋放其它的內存拿來此處使用,如果可以,就成功,否則發出bad_alloc異常。

以上就是整個第二級空間配置器的設計。

總結來說:第一級負責分配大內存,直接使用malloc,第二級使用內存池加上自由鏈表來分配。

參考資料:

1. 《STL源碼剖析》侯捷

=============================================================================================

Linux應用程序、內核、驅動、後臺開發交流討論羣(745510310),感興趣的同學可以加羣討論、交流、資料查找等,前進的道路上,你不是一個人奧^_^。

 

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