STL中的記憶體分配方式

2021-08-08 22:46:31 字數 2261 閱讀 4037

**(

在stl中考慮到小型區塊所可能造成的記憶體碎片問題,sgi stl設計了雙層級配置器,第一級配置器直接使用malloc()和free();第二級配置器則視情況採用不同的策略:當配置區塊超過128bytes 時,則視之為足夠大,便呼叫第一級配置器;當配置區塊小於128bytes時,則視之為過小,為了降低額外負擔,便採用複雜的記憶體池的方式來整理,而不再求助於第一級配置器。

內定義了兩個template,乙個是 __malloc_alloc_template,這是sgi stl的一級配置器,它的allocate()直接使用malloc()而deallocate()直接使用free(),同時,它模擬c++的 set_new_handler()處理記憶體不足的狀況。

第二個是__default_alloc_template,它維護了16個free list,每個list上集合著大小分別為8,16,24,…128大小的記憶體塊。記憶體池以malloc()配置而得,如果記憶體不足,轉呼叫第一級配 置器,因為那裡設定了記憶體不足的處理程式。如果請求的記憶體塊大小大於128bytes,就轉呼叫第一級配置器。另外定義了兩個alloc,乙個是 debug_alloc,每次配置一塊記憶體時,都會配置比需求多8byte的空間以儲存空間大小,通過assert語句來檢查會不會記憶體溢位。另乙個是 ******_alloc,定義了兩個版本的allocate和deallocate,它們都只是單純的轉呼叫。sgi stl容器全都使用******_alloc介面。free-list的節點巧妙地使用了乙個union結構來管理鍊錶:

每次配置器需要向系統要記憶體的時候,都不是按客戶需求向系統申請的,而是一次性向系統要了比需求更多的記憶體,放在記憶體池裡,有乙個free_start和 free_end指示剩餘的空間(也就是說記憶體池剩餘的空間都是連續的,因此每次重新向system heap要空間的時候,都會把原先記憶體池裡沒用完的空間分配給合適的free list。)當free-list中沒有可用區塊了的時候,會首先從記憶體池裡要記憶體,同樣,也不是以按客戶需求要多少塊的,而是一次可能會要上20塊,如 果記憶體池內空間允許的話,可能會得到20個特定大小的記憶體,如果記憶體池給不了那麼多,那麼就只好盡力給出;如果連乙個都給不出,那麼就要開始向系統即 system heap要空間了。換算的標準是bytes_to_get=2*total_bytes+round_up(heap_size>>4)。這 個時候使用的是malloc,如果沒成功,就嘗試著從大塊一點的freelist那裡要乙個來還給記憶體池,如果還是不行,那麼會呼叫第一級空間配置器的 malloc::allocate,看看out-of-memory機制能做點什麼不。

總結起來整個過程大概是這樣的,假設我們向系統要x大小的記憶體,

(1)x大於128byte,用第一級配置器直接向系統malloc,至於不成功的處理,過程仿照new,通過set_new_handler來處理,直到成功返回相應大小的記憶體或者是丟擲異常或者是乾脆結束執行;

(2)x小於128byte,用第二級配置器向記憶體池相應的free_list要記憶體,如果該freelist上面沒有空閒塊了,

(2.1)從記憶體池裡面要記憶體,預設是獲得20個節點,如果記憶體池中剩餘的空間不能完全滿足需求量,但足夠**乙個(含)以上的區塊,則應盡力滿足需求。

(2.2) 如果乙個都不能夠滿足的話,則從系統的heap裡面要記憶體給到記憶體池,換算的標準是 bytes_to_get=2*total_bytes+round_up(heap_size>>4),申請的大小為需求量的兩倍加上乙個 附加值,如果記憶體池中還有剩餘的記憶體,則將殘餘零頭分配給適當的free list,這時使用的是系統的malloc,如果要不到:

(2.3)從比較大的freelist那裡要記憶體到記憶體池,如果還是要不到:

(2.4) 從系統的heap裡面要記憶體給到記憶體池,換算標準跟2.2一樣,但是這時候使用的是第一級配置器的allocate,主要是看看能不能通過 out_of_memory機制得到一點記憶體。所以,freelist總是從記憶體池裡要記憶體的,而記憶體池可能從freelist也可能從系統heap那裡 要記憶體。

sgi stl的alloc的主要開銷就在於管理這些小記憶體,管理這些小記憶體的主要開銷就在於,每次freelist上的記憶體塊用完了,需要重新要空間,然後建立 起這個list來。freelist上的記憶體,會一直保留著直到程式退出才還給系統。但這不會產生記憶體洩漏,一來是管理的都是小記憶體,二來是,占用的記憶體 只會是整個程式執行過程中小記憶體佔用量最大的那一刻所占用的記憶體。

記憶體分配方式

記憶體分配方式有三種 1 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的 整個執行期間都存在。例如全域性變數,static 變數。2 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函 數執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指...

記憶體分配方式

記憶體分配方式有三種 1 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個 執行期間都存在。例如全域性變數,static變數。2 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執 行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令...

記憶體分配方式

乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其 操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os回 收 注意它與資料結構中的堆是兩回事,分配方...