1. 程式人生 > >STL初探——__default_alloc_template內存池

STL初探——__default_alloc_template內存池

滿足 thread idt turn 徹底 align 其他 函數 return

  _S_chunk_alloc() 函數負責從內存池取出空間給free-list,如果內存池內存充足,則直接拿出足夠的內存塊給自由鏈表,如果內存不夠所有需求但是對一小塊需求能滿足,則拿出一小塊內存給自由鏈表並返回,如果一點兒內存也沒有,則進行遍歷壓榨,最終如果真的沒有,就只能求助於第一級配置器。代碼如下:

template <bool __threads, int __inst>
char*
__default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, 
                                                            
int& __nobjs) { char* __result; size_t __total_bytes = __size * __nobjs; size_t __bytes_left = _S_end_free - _S_start_free; //內存池剩余空間 if (__bytes_left >= __total_bytes) //滿足內存需求 { __result = _S_start_free; _S_start_free += __total_bytes;
return(__result); } else if (__bytes_left >= __size) //滿足至少一個區塊的需求 { __nobjs = (int)(__bytes_left/__size); __total_bytes = __size * __nobjs; __result = _S_start_free; _S_start_free += __total_bytes; return(__result); }
else //完全不滿足需求 { size_t __bytes_to_get = 2 * __total_bytes + _S_round_up(_S_heap_size >> 4); //利用剩下的一點點零頭. if (__bytes_left > 0) { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__bytes_left); ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list; *__my_free_list = (_Obj*)_S_start_free; } _S_start_free = (char*)malloc(__bytes_to_get); if (0 == _S_start_free) { size_t __i; _Obj* __STL_VOLATILE* __my_free_list; _Obj* __p; //看free-list是否還有內存區塊 for (__i = __size; __i <= (size_t) _MAX_BYTES; __i += (size_t) _ALIGN) { __my_free_list = _S_free_list + _S_freelist_index(__i); __p = *__my_free_list; //有的話,編入,並循環調用自身,直至徹底使用所有零頭 if (0 != __p) { *__my_free_list = __p -> _M_free_list_link; _S_start_free = (char*)__p; _S_end_free = _S_start_free + __i; return(_S_chunk_alloc(__size, __nobjs)); //反復壓榨內存 } } //執行到了這一步,說明沒內存了,_S_end_free初始化置於零,並調用第一級配置器配置內存重新設定_S_start_free。 _S_end_free = 0; _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get); } _S_heap_size += __bytes_to_get; _S_end_free = _S_start_free + __bytes_to_get; // return(_S_chunk_alloc(__size, __nobjs)); } }

  為了好懂,我們這樣想,假設程序開始運行,客端就開始調用_S_chunk_alloc(32,20)函數,假設 malloc() 一次性配置40個32bytes的內存區塊,其中20個作為函數返回值,之後1個被交給客戶端,剩下19個交給 free-list[3] 維護,要的時候再去取即可。另外20個留給內存池。接下來客端調用_S_chunk_alloc(64,20),64個是歸 free-list[7] 維護的,然而 free-list[7] 空空如也,必須向內存池尋求支持,內存池能夠供應 20 x 32 / 64 = 10個區塊,就把這10個區塊返回,其中1個交給客戶端,剩下九個交給 free-list[7] 維護,內存池空了,假設接下來再調用 _S_chunk_alloc(96,20) ,64個是歸 free-list[11] 維護的,然而 free-list[11] 空空如也,必須向內存池尋求幫助,而內存池也是空的,於是又開始調用 malloc() 分配 20 +n 個 96大小的內存塊,其中20內存塊返回,一個被交付,剩下19個交給 free-list[11] 維護,而還有n個 96 大小的內存塊就交給內存池維護......

  如果最終內存裏面的堆區沒有內存了,無法為內存池註入新的內存,malloc() 行動失敗,_S_chunk_alloc()就在free-list裏尋找有沒有 “尚未應用區塊,且區塊足夠大”,找到就挖出一塊並交出,找不到就調用第一級配置器,第一級配置器其實也是用 malloc() 來配置內存,但它有 out-of-memory 處理機制(類似new handler),或許有機會釋放其他的內存並拿來此處使用,如果可以就內存配置成功,否則就拋出 bad_alloc()異常。

技術分享

STL初探——__default_alloc_template內存池