當你將元素加入容器中,容器必須分配更多內存以保存這些元素,因而它們向其模板參數 Allocator 發出申請,該模板參數每每被另名爲(aliased to)allocator_type。甚至你將 chars 添加到 string class 也是如此,由於 string 也算是一個正規 STL 容器。數組
template <class T, class Allocator=allocator<T>> class vector; template <class T, class Allocator=allocator<T>> class list; template <class T, class Allocator=allocator<T>> class deque;
每一個元素類型爲 T 的容器(container-of-T) 的 Allocator 模板參數默認爲 allocator<T>。其接口只有大約 20 個 public 聲明,包括嵌套的(nested) typedefs 和成員函數。最終要的兩個函數是:緩存
T *allocate(size_type n, const void *hint = 0); void deallocate(T *p, size_type n);
n 指的是客戶申請的元素個數,不是指空間數量(字節數)cookie
這些空間都是經過調用 ::operator new 得到,但什麼時候調用以及多麼頻繁調用,並沒有具體指定多線程
最容易知足需求的作法就是每當容器須要內存就調用 operator new, 每當容器釋放內存就調用 operator delete。這種作法比起分配大塊內存並緩存(caching)而後徐徐小塊使用固然慢,優點則是能夠在極大範圍的硬件和操做系統上有效運做app
__gnu_cxx::new_allocator
實現出簡樸的 operator new 和 operator delete 語義函數
template<typename _Tp> class new_allocator { .... pointer allocate(size_type __n, const void*=0) { .... return static_cast<_Tp*>(operator new(__n * sizeof(_Tp))); } void deallocate(pointer __p, size_type) { ::operator delete(__p); } };
__gnu_cxx::malloc_allocator
template <typename _Tp> class malloc_allocator { pointer allocate(size_type __n, const void*=0) { ... pointer __ret = ...(std::malloc(__n * sizeof(_Tp))); } void deallocate(pointer __p, size_type) { std::free(...(__p)); } };
另外一種作法就是使用智能型 allocator, 將分配所得的內存加以緩存(cache、內存池)。這種額外機制能夠數種形式呈現:測試
能夠是個 bitmap index, 用以索引至一個以 2 的指數倍成長的籃子(exponentially increasing power-of-two-sized buckets)spa
也能夠是個相較之下比較簡易的 fixed-size pooling cache操作系統
這裏所說的 cache 被程序內的全部容器共享,而 operator new 和 operator delete 不常常被使用,這可帶來速度上的優點(底層malloc也是一個複雜的內存池,速度優點並不明顯,主要是減小了cookie的使用)。使用這類技巧的 allocators 包括:線程
__gnu_cxx::bitmap_allocator
一個高效能 allocator,使用 bit-map 追蹤被使用和未被使用(used and unused)的內存塊
__gnu_cxx::pool_allocator
__gnu_cxx::__mt_alloc
Class allocator 只擁有 typedef, constructor 和 rebind 等成員。它繼承子一個 high-speed extension allocators。也所以,全部分配和歸還(allocation and deallocation) 都取決於該 base class, 而這個 base class 也許是終端用戶沒法觸碰和操做的(user-configurable)
很難挑選出某個分配策略說它能提供最大利益而不至於令某些行爲過分劣勢。事實上,就算要挑選何種典型動做以測量速度,都是一種困難
GNU C++ 提供三項綜合測試(three synthetic benchmarks)用以完成 C++ allocators 之間的速度對比:
Insertion, 通過屢次 insertions 後各類 STL 容器將擁有某些及大量。分別測試循序式(sequence)和關聯式(assiciative)容器
多線程環境中的 insertion and erasure, 這個測試展現 allocator 歸還內存的能力,以及測量線程之間對內存的競爭
A threaded producer/consumer model, 分分別測試循序式(sequence)和關聯式(assiciative)容器
令兩個智能型 allocator:
__gnu_cxx::debug_allocator(用處極少)
這是一個外覆器(wrapper), 可包覆於任何 allocator 之上,它把客戶的申請量添加一些,而後由 allocator 迴應,並以那一小塊額外內存放置 size 信息。一旦 deallocate() 收到一個 pointer, 就會檢查 size 並以 assert() 保證吻合
__gnu_cxx::array::allocator
容許分配一已知固定大小(known and fixed size)的內存塊,內存來自 std::array objects(原生的靜態數組)。用上這個 allocator, 大小固定的容器(包括 std::string) 就無需再調用 ::operator new 和 operator delete。 這就容許咱們使用 STL abstractions 而無需再運行期 "添亂"、增長開銷。甚至再 program startup 狀況下也可以使用(動態分配還沒準備好的狀況下)