一般容器都需要一定空間存放資料,allocator就是用來配置空間的,sgi的allocator配置的物件時記憶體。
乙個allocator通常包含兩個部分,一是記憶體配置和記憶體釋放(allocate的deallocate),二是物件構造和析構(construct和destory)。
#ifndef _jjalloc_
#define _jjalloc_
#include
//for placement new
#include
//for ptrdiff_t,size_t
#include
//for uint_max
#include
//for cerr
namespace jj
return tmp;
}template
<
class
t>
inline
void
_deallocate
(t* buffer)
template
<
classt1,
class
t2>
inline
void
_construct
(t1*p,
const t2& value)
template
<
class
t>
inline
void
_destroy
(t* ptr)
template
<
class
t>
class
allocator;
pointer allocate
(size_type n,
const
void
* hint=0)
void
deallocate
(pointer p,size_type n)
void
construct
(pointer p,
const t& value)
void
destroy
(pointer p)
pointer address
(reference x)
const_pointer const_address
(const_reference x)
size_type max_size()
const;}
;}//end of namespace jj
#endif _jjalloc_
重點是jj空間中四個模板函式:
__allocate函式模板採用了operator new來配置記憶體,即分配一塊未構造的、原始的記憶體空間。
__deallocate利用operator delete釋放上面分配的記憶體。
__construct採用定位new在給定的記憶體位址上構造物件。
__destory執行物件的析構動作。
四個部分構成了空間配置器的基礎。
sgi提供了兩個空間配置器,其中標準的allocator與上面提供的簡單空間配置器類似,效率並不高,也不推薦使用。
下面介紹sgi特殊空間配置器
sgi特殊的空間配置器稱為alloc,alloc也是由之前講述的兩部分構成:一是記憶體配置和記憶體釋放(allocate的deallocate),二是物件構造和析構(construct和destory)。
3.1.1構造和析構
以下原始碼在 。
構造工具和之前介紹的簡單空間配置器並無區別,主要區別在析構操作上,提供了兩個個版本的析構工具,乙個是銷毀單個物件,另外乙個是銷毀多個:
template
<
class
_tp>
inline
void
_destroy
(_tp* __pointer)
template
<
class
_forwarditerator
>
inline
void
_destroy
(_forwarditerator __first, _forwarditerator __last)
第二個版本通過__value_type判斷是否有物件是否有trivial destructor(無關痛癢的析構函式),然後呼叫不同的__destroy_aux,如果有執行它的析構函式(_destroy(&*__first)),如果沒有就什麼也不做,因此提高了效率:
template
<
class
_forwarditerator
>
void
__destroy_aux
(_forwarditerator __first, _forwarditerator __last, __false_type)
template
<
class
_forwarditerator
>
inline
void
__destroy_aux
(_forwarditerator, _forwarditerator, __true_type)
3.1.2空間的配置和釋放
以下原始碼在
sgi在空間配置上考慮了以下問題:
c++的記憶體配置基本操作是:operator new和operator delete,其相當於c語言的malloc和free函式。
考慮記憶體碎片的問題,sgi配置器採用雙層級配置器:
不論採用第一級還是第二級,sgi都為他們包裝了乙個介面以供使用(******_alloc)。
第一級配置器
第一級配置器採用malloc、free、realloc等執行實際記憶體操作,而不是使用operator new,因此不能直接運用c++ new-handler機制(即如果operator new無法完成操作,在丟擲bad_alloc之前會先呼叫客戶指定的處理程式,此程式稱為new-handler)。需要自己實現new-handler機制:
static
void(*
set_malloc_handler
(void
(*f)()
))()
template
<
int inst>
void
* __malloc_alloc_template
::oom_malloc
(size_t n)
(*my_malloc_handler)()
;//呼叫new-handler
result =
malloc
(n);
if(result)
return
(result);}
}
如果malloc不成功,會改用oom_malloc不斷申請,如果客戶端未設定new-handler,則丟擲異常。
第二級配置器
第二級配置器維護16個free-lists,分別管理8、16、24、32…120、128大小的區塊,客戶端配置記憶體時過程如下:
先從free-list中申請滿足大小要求並且最小的區塊,申請成功就返回給客戶端並且該free-list的指標指向下乙個區塊。
如果在該free-list中沒有申請到,就呼叫refill從記憶體池中申請20區塊大小填充該free-list。
記憶體池的操作如下:
3. 如果記憶體池水量充足,就調出20個區塊返回。
4. 如果水量不足,但還夠乙個以上區塊,就調出這些區塊然後返回。
5. 如果水量連乙個區塊都不足以提供,就從系統heap申請記憶體。在申請前,先把記憶體池中的零頭分配給free-list,比如記憶體池中還剩35位元組,就分配給區塊大小為32的free-list。
6. 從系統申請40+n的記憶體,然後將第乙個區塊交給客戶端,將剩餘19個區塊交給free-list維護,剩下的20+n個留給記憶體池。
7. 如果整個系統heap都不夠了,就查詢是否還有足夠大且沒有使用的free-list,然後釋放這些區塊(大的放入記憶體池,小的零頭被編入free-list,通過遞迴呼叫自己實現)。
參考:stl原始碼剖析
STL原始碼剖析 空間配置器
看過stl空間配置器的原始碼,總結一下 1 stl空間配置器 主要分三個檔案實現,stl construct.h 這裡定義了全域性函式construct 和destroy 負責物件的構造和析構。stl alloc.h檔案中定義了 一 二兩級配置器,彼此合作,配置器名為alloc.stl uninit...
STL原始碼剖析 空間配置器
allocator是空間配置器而不是記憶體配置器,空間不一定是記憶體,也可以是磁碟或其他輔助儲存介質。但sgi stl提供的配置器配置的物件是記憶體。sgi標準的空間配置器,std alloctor sgi定義了乙個符合部分標準,名為alloctor的配置器,效率不高,只把c 的 operator ...
STL原始碼剖析 空間配置器
由於物件的建立分為分配記憶體和呼叫建構函式兩部分,stl allocator使用alloc allocate 來分配記憶體,construct 構造物件。construct 函式只有乙個泛化的版本,destroy 函式有乙個泛化的針對迭代器的版本,destroy aux 根據是否需要呼叫析構函式進行...