1. 程式人生 > >《STL原始碼剖析》學習筆記

《STL原始碼剖析》學習筆記

第二章:空間配置器(allocator)

考慮到小型區塊可能造成的記憶體破碎問題,SGI設計了雙層級配置器。

當配置區塊超過128bytes時,便呼叫第一級配置器,即直接使用malloc() free();

SGI的第一級配置器的allocate()和realloc()都是在呼叫malloc()和realloc()不成功後,改呼叫oom_malloc()和oom_realloc(),後兩者都有內迴圈,不斷呼叫“記憶體不足處理例程“,期望在某次呼叫後,獲得足夠的記憶體而圓滿完成任務,但如果“記憶體不足處理例程”未被客端設定,oom_malloc()和oom_realloc()便不客氣的呼叫__THROW_BAD_ALLOC,丟出bad_alloc異常資訊,或利用exit(1)中止程式。

當配置區塊小於128bytes時,採用複雜的memory pool整理方式:

每次配置一大塊記憶體,並維護對應之自由連結串列free-list,下次若再有相同大小的記憶體需求,就直接從free-list中撥出,如果客端釋放小額區塊,就由配置器回收到free-list中,為方便管理,第二級配置器主動將任何小額區塊的記憶體需求量上調至8的倍數,並維護16個free-list,各自管理大小分別為8,16,24,32,40,48, 56,64,72,80,88,96,104,112, 120,128bytes的區塊

假設程式一開始,客端就呼叫chunk_alloc(32, 20),於是malloc()配置40個32bytes區塊,其中第一個交出,另19個交給free-list[3]維護,餘20個留給記憶體池,接下來客端呼叫chunk_alloc(64, 20),此時free-list[7]空空如也,必須向記憶體池要求支援,記憶體池只夠供應(32*20)/64=10個64bytes區塊,就把這10個區塊返回,第一個交給客端,餘9個由free-list[7]維護,此時記憶體池全空,接下來再呼叫chunk_alloc(96, 20),此時free-list[11]空空如也,必須向記憶體池要求支援,而記憶體池此時也是空的,於是以malloc()配置40+n(附加量)個96bytes區塊,其中第一個交出,另19個交給free_list[11]維護,餘20+n個區塊留給記憶體池;

萬一整個system heap空間都不夠了,malloc()行動失敗,chunk_alloc()就四處尋找有無“尚有未用區塊,且區塊夠大”之free-list,找到了就挖一塊交出,找不到就呼叫第一級配置器。第一級配置器也是使用malloc()配置記憶體,但它有out-of-memory處理機制,或許有機會釋放其他的記憶體拿來此處使用,如果失敗,發出bad_alloc異常。

第四章

一,vector

1,vector的記憶體不是固定的是動態的,每當size()==capacity(),vector會分配一塊原來長度兩倍的空間,並將原來的每個元素拷貝到新空間中,最後釋放舊空間。

2,vector維護的是一個連續的空間,迭代器是元素型別的普通指標。

3,vector類中有三個成員都是迭代器,分別start指向目前使用空間的頭,finish指向目前使用空間的尾,end_of_storage指向目前可用空間的尾。

4,對vector的任何操作,一旦引起空間重新配置,指向原vector的所有迭代器就都失敗了。

二,list

1,list每次插入或刪除一個元素,就配置或釋放一個元素空間,不會浪費空間,對於任何位置的元素插入或刪除,list永遠是常數時間。

2,STLlist是一個雙向(環形)連結串列,insert插入和splice接合都不會造成原有的list迭代器失效,list的erase刪除操作,只有被刪除的元素的迭代器失效,其他的迭代器不會失效。

三,deque

1,deque是可以在頭尾兩端分別做元素的插入和刪除操作的一種雙向開口的分段連續空間。

2,每個deque有一個map,map是一個線性陣列,陣列的每個元素指向一段連續線性空間,deque中的真正元素儲存在每一段連續線性空間中,每個deque都有兩個start和finish迭代器結構,該結構有四個成員,cur指向當前被訪問到的元素,first指向這段連續空間的第一個元素,last指向這段連續空間的最後一個元素

3,map最小元素個數為8,若空間不夠,map可以重置。

4,stack和queue由deque作為底層實現。

四,priority_queue

1,實現機制是heap演算法。

2,連續線性空間。