在STL中考慮到小型區(qū)塊所可能造成的內(nèi)存碎片問題,SGI STL設計了雙層級配置器,第一級配置器直接使用malloc()和free();第二級配置器則視情況采用不同的策略:當配置區(qū)塊超過128bytes 時,則視之為足夠大,便調(diào)用第一級配置器;當配置區(qū)塊小于128bytes時,則視之為過小,為了降低額外負擔,便采用復雜的內(nèi)存池的方式來整理,而不再求助于第一級配置器。
每次配置器需要向系統(tǒng)要內(nèi)存的時候,都不是按客戶需求向系統(tǒng)申請的,而是一次性向系統(tǒng)要了比需求更多的內(nèi)存,放在內(nèi)存池里,有一個free_start和 free_end指示剩余的空間(也就是說內(nèi)存池剩余的空間都是連續(xù)的,因此每次重新向system heap要空間的時候,都會把原先內(nèi)存池里沒用完的空間分配給合適的free list。)當free-list中沒有可用區(qū)塊了的時候,會首先從內(nèi)存池里要內(nèi)存,同樣,也不是以按客戶需求要多少塊的,而是一次可能會要上20塊,如 果內(nèi)存池內(nèi)空間允許的話,可能會得到20個特定大小的內(nèi)存,如果內(nèi)存池給不了那么多,那么就只好盡力給出;如果連一個都給不出,那么就要開始向系統(tǒng)即 system heap要空間了。換算的標準是bytes_to_get=2*total_bytes+ROUND_UP(heap_size>>4)。這個時候使用的是malloc,如果沒成功,就嘗試著從大塊一點的freelist那里要一個來還給內(nèi)存池,如果還是不行,那么會調(diào)用第一級空間配置器的 malloc::allocate,看看out-of-memory機制能做點什么。
假設我們向系統(tǒng)要x大小的內(nèi)存,
(1)x大于128byte,用第一級配置器直接向系統(tǒng)malloc,至于不成功的處理,過程仿照new,通過set_new_handler來處理,直到成功返回相應大小的內(nèi)存或者是拋出異?;蛘呤歉纱嘟Y束運行;
(2)x小于128byte,用第二級配置器向內(nèi)存池相應的free_list要內(nèi)存,如果該freelist上面沒有空閑塊了,
(2.1)從內(nèi)存池里面要內(nèi)存,缺省是獲得20個節(jié)點,如果內(nèi)存池中剩余的空間不能完全滿足需求量,但足夠供應一個(含)以上的區(qū)塊,則應盡力滿足需求。
(2.2) 如果一個都不能夠滿足的話,則從系統(tǒng)的heap里面要內(nèi)存給到內(nèi)存池,換算的標準是 bytes_to_get=2*total_bytes+ROUND_UP(heap_size>>4),申請的大小為需求量的兩倍加上一個 附加值,如果內(nèi)存池中還有剩余的內(nèi)存,則將殘余零頭分配給適當?shù)膄ree list,這時使用的是系統(tǒng)的malloc,如果要不到:
(2.3)從比較大的freelist那里要內(nèi)存到內(nèi)存池,如果還是要不到:
(2.4) 從系統(tǒng)的heap里面要內(nèi)存給到內(nèi)存池,換算標準跟2.2一樣,但是這時候使用的是第一級配置器的allocate,主要是看看能不能通過 out_of_memory機制得到一點內(nèi)存。所以,freelist總是從內(nèi)存池里要內(nèi)存的,而內(nèi)存池可能從freelist也可能從系統(tǒng)heap那里 要內(nèi)存。
SGI STL的alloc的主要開銷就在于管理這些小內(nèi)存,管理這些小內(nèi)存的主要開銷就在于,每次freelist上的內(nèi)存塊用完了,需要重新要空間,然后建立 起這個list來。freelist上的內(nèi)存,會一直保留著直到程序退出才還給系統(tǒng)。但這不會產(chǎn)生內(nèi)存泄漏,一來是管理的都是小內(nèi)存,二來是,占用的內(nèi)存 只會是整個程序運行過程中小內(nèi)存占用量最大的那一刻所占用的內(nèi)存。
部分文章來源與網(wǎng)絡,若有侵權請聯(lián)系站長刪除!