STL 記憶體管理

2021-08-19 23:18:56 字數 3741 閱讀 2735

stl有很多種allocator,根據c++的標準,stl的allocator把物件的申請和釋放分為四個步驟:

(1) 申請記憶體空間,對應的函式是allocator::allocate()

(2) 執行建構函式,對應的函式是allocator::construct()

(3) 執行析構函式,對應的函式是allocator::destory()

(4) 釋放記憶體空間,對應的函式是allocator::的allocate()

1._default_alloc_template分配器

這個分配器採用的是記憶體池的思想,有效的避免了內碎片的問題,內碎片是已經被分配出去了,外碎片是由於太小無法分配出去的空間。

(1)如果申請的空間大於128

bytes,就將申請的操作移交給_malloc_alloc_template分配器去處理,如果申請記憶體大小小於128

bytes,就從本分配器維護的記憶體池中分配記憶體。

(2)該分配器用空閒鍊錶的方式維護記憶體池中的空閒空間,空閒鍊錶的形狀類似於下圖所示:

s_free_list是這些空閒分割槽連的起始位址組成的陣列,大小為16,這16個鍊錶中,每個鍊錶中的空閒空間大小都是固定的,第乙個鍊錶的空閒大小是8

bytes,一次是16,24,32,40,48,56,64,72,80,88,96,104,112,120,128

bytes。

此外有三個指標,s_start_free,s_end_free,s_heap_size,他們分別 指向整個記憶體池的起始位址,結束位址,和可用空間的大小。

分配記憶體的過程

(1)如果申請的記憶體空間大於128bytes,就交給第一分配器處理,如果申請的記憶體空間小於128bytes,就採用當前的第二分配器處理

(2)採用第二分配器,分配器首先將申請記憶體的大小調製8的倍數n,並根據n找出對應的空閒鍊錶位址_my_free_list

(3)如果空閒鍊錶有可用的空閒塊,則將此空閒塊返回並跟新_my_free_list,否則進行(4)

(4)到這一步,說明_my_free_list中沒有可用的空閒塊,分配器就按照下面的上進行分配:

【1】試著用_s_chunk_alloc()申請大小為n*20的記憶體空間(但是不一定能申請到這麼大的記憶體空間)

【2】如果申請到這麼大的空間,則返回給使用者,否則進行下一步

【3】將申請到的n*x的記憶體塊取出乙個返回給使用者,其餘的記憶體塊連線到空閒鍊錶_my_free_list

**_s_chunk_alloc()的作用主要是從記憶體池取空間給空閒鍊錶使用**

_s_chunk_alloc()的具體過程如下:

【1】如果_s_start_free和_s_end_free之間有足夠的空間分配n*20的記憶體空間,更新_s_start_free,並返回申請到的記憶體空間的起始位址,否則進行下一步

【2】如果_s_start_free和_s_end_free之間有足夠的空間分配n的記憶體空間,則分配整數倍於n的記憶體空間,更新_s_start_free,由nobj返回這個整數,並返回申請到的記憶體空間的起始位址,否則進行下一步

【3】到這一步說明記憶體池連一塊大小為n的記憶體都沒有了,此時如果記憶體池中還有一些記憶體,那麼他的大小一定小於n,將這些記憶體插入到對應大小的空閒分割槽鏈中

【4】呼叫malloc向執行時庫申請大小為(2

*n*20+附加量)的記憶體空間,如果申請成功,則更新s_start_free,s_end_free,s_heap_size,並重新呼叫_s_chunk_alloc(),否則進行下一步

【5】到這一步,說明malloc申請失敗,這時分配器一次遍歷16個空閒分割槽連,只要有乙個空閒鏈,就釋放該鏈中的乙個節點,重新呼叫_s_chunk_alloc()

記憶體釋放的過程

記憶體釋放,他接受兩個引數,乙個是要指向要釋放的記憶體塊的指標p,另乙個表示要釋放記憶體塊的大小n,如果n大於128

bytes,則交給第一分配器處理,否則就找出對應的空閒鍊錶,將區塊**。

2.第一級分配器_malloc_alloc_templatemalloc()函式進行記憶體分配

(1) malloc他有乙個將可用的記憶體快連線成乙個長長的列表的所謂空閒鍊錶

(2) 呼叫malloc函式時,它沿連線表尋找乙個大到足以滿足使用者請求所需的記憶體快,然後將記憶體塊一分為二(一塊的大小與使用者請求的大小相等,另一塊大小是剩下的位元組),接下來將分配給使用者的那塊記憶體傳給使用者,並將省下的那塊返回到連線表上

(3) 呼叫free函式時,它將使用者釋放的記憶體快連線到空閒鏈上,到最後空閒鏈上會被切成很多小記憶體片段,如果這時候使用者申請乙個大的記憶體片段,那麼空閒鏈上就可能沒有滿足使用者需求的片段,於是malloc函式請求延時,並在空閒鍊錶上檢查記憶體片段,對它們進行整理,將相鄰的小空心塊,合併成較大的記憶體塊

(4) glibc維護的不止乙個不定長的記憶體塊鍊錶,而是好幾個,每乙個這種鍊錶負責乙個大小範圍,這種做法有效的減少了分配大記憶體時的遍歷開銷

(5) glibc另外的策略就是不只維護乙個空閒鍊錶,而是另外在維護乙個緩衝鍊錶和乙個高速緩衝鍊錶

(6) 在分配的時候首先在快取記憶體中查詢,失敗之後再在空閒鍊錶上查詢,如果找到的記憶體塊比較大,那麼將切割之後的剩餘記憶體塊插入到快取鍊錶中

(7) 如果空閒鍊錶查詢失敗,那麼就往快取煉表裡查詢,如果還是沒有合適的空閒塊,就像記憶體申請比請求數更大的記憶體塊

(8) 在對記憶體進行了free呼叫之後,我們需要做的是,把他們標記為未使用,並且在呼叫malloc時,我們可以定位到沒有被使用的記憶體塊(這就解釋了為什麼free之後堆上的記憶體沒有被釋放)

(9) malloc申請記憶體主要是在heap區域分配的,程序所面對的虛擬記憶體位址空間,都是按頁對映到物理記憶體位址,才能真正使用,受物理儲存容器限制,整個堆虛擬記憶體空間不可能全部對映到實際的物理記憶體。linux對堆的管理示意圖:

linux維護了乙個break指標,這個指標指向堆空間的某個位址,從堆起始位址到break之間的位址空間為對映好的,可以供程序訪問,而從break往上,是為對映的位址空間,如果訪問這段空間,則長鬚會報錯。要增加乙個程序實際的可用堆的大小,就要把break往高位址移動,linux通過brk和sbrk系統呼叫操作break指標

(10) linux是按頁進行記憶體對映的,所以如果break的設定沒有按頁大小對齊,系統實際上會在最後對映乙個完整頁,從實際已經對映的空間比break指向的地方要大一些,但是使用break位址之後的位址就很危險了

free()函式釋放記憶體的過程

(1) free函式是將之前用malloc分配的空間還給程式或作業系統,也就是釋放記憶體,讓它重新得到自由

(2) free釋放的指標指向記憶體,釋放記憶體後把指標指向為空,防止指標在後面又一不小心被解引用

(3) free函式的引數非常簡單,只有乙個引數,只要把指向申請空間的指標傳遞給free中的引數就完成了釋放工作

STL記憶體管理

linux記憶體分配管理 實現自己的malloc stl是一套非常高效的c 庫,提到記憶體管理,怎麼能少了他呢,花了近一天的時間來剖析這個。stl記憶體分配分為兩級,為什麼分為兩級,就比如你為了買一根普通的皮帶,去漢正街批發市場,別人不一定賣給你 親身經歷 只有一次性購買大量的貨才會去批發市場,商家...

STL記憶體管理

過年在家無事看了 stl原始碼剖析 開學了將看過的東西總結一下,以防忘記。先從stl的記憶體管理開始總結。掌管stl記憶體控制的是乙個叫空間介面卡 alloc 的東西。stl有兩個空間介面卡,sgi標準空間介面卡 allocate 和sgi特殊的空間介面卡 alloc 前者只是對c 的new和del...

stl記憶體管理

stl提供了很多泛型容器,如vector,list和map。程式設計師在使用這些容器時只需關心何時往容器內塞物件,而不用關心如何管理記憶體,需要用多少記憶體,這些stl容器極大地方便了c 程式的編寫。例如可以通過以下語句建立乙個vector,它實際上是乙個按需增長的動態陣列,其每個元素的型別為int...