1. allocator 基本介紹html
分配器(allocator))是C ++標準庫的一個組件, 主要用來處理全部給定容器(vector,list,map等)內存的分配和釋放。C ++標準庫提供了默認使用的通用分配器std::allocator,可是,也能夠由程序員本身提供自定義分配器。 c++
2. allocator 標準庫規範程序員
咱們去看std中的stl分配器實現,會發現不管你的實現思路怎麼變,全部模板類中的接口和成員變量都是同樣的,那麼這是由於C++標準庫在制定分配器時,是有提出硬性標準的,具體接口和成員變量以下: 緩存
STD 標準規範(GNU ISO C++ Library 5.2.1):多線程
typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; typedef _Tp value_type; void construct(pointer __p, const _Tp& __val) { ::new((void *)__p) value_type(__val); } void destroy(pointer __p) { __p->~_Tp(); } size_type max_size() const _GLIBCXX_USE_NOEXCEPT { return size_t(-1) / sizeof(_Tp); } address(const_reference __x) const _GLIBCXX_NOEXCEPT deallocate(pointer, size_type); allocate(size_type __n, const void* = 0); template<typename _Tp1> struct rebind { typedef allocator<_Tp1> other; };
對於上面這一段接口和變量,其中一些在其餘容器的分析中,咱們會常常看到,下面對於其中有疑問的點咱們來解釋一下:性能
size_type:this
爲 unsigned 類型 , 表示容器中元素長度或者下標,例:vector
difference_type:.net
爲 signed 類型 , 表示迭代器差距, vector
size_t(-1):
size_t 爲 unsigned 類型,傳入 -1 得到size_t該系統的最大值。
3. GNU ISO C++ Library 中STL分配器實現
1. 默認分配器:
按照標準規範,標準庫中stl實現的分配器,對外接口,成員變量幾乎都同樣,只是接口內部實現有區別,那麼咱們看一下具體實現流程, 首先看一下容器默認的分配器std::allocator<_Tp>。 看代碼咱們會發現,默認分配器真正的實現是在new_allocator.h頭文件中作的,頭文件具體調用順序爲:allocator.h -> c++allocator.h -> new_allocator.h, 看代碼咱們知道,在前面兩個頭文件中基本沒作什麼,真正的實現爲模板類new_allocator。 關鍵代碼以下所示:
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> class new_allocator { public: typedef _Tp* pointer; typedef const _Tp* const_pointer; // NB: __n is permitted to be 0. The C++ standard says nothing // about what the return value is when __n == 0. pointer allocate(size_type __n, const void* = 0) { if (__n > this->max_size()) std::__throw_bad_alloc(); return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); } // __p is not permitted to be a null pointer. void deallocate(pointer __p, size_type) { ::operator delete(__p); } } _GLIBCXX_END_NAMESPACE_VERSION } // namespace
咱們看一下分配和釋放的接口allocate和deallocate,實現上只是單純的將::operator new和::operator delete進行了一下封裝,沒用作特殊處理。
固然,若是咱們不特別說明,直接在Linux系統下使用標準C++的stl容器,在爲容器元素分配內存時,使用的方式就是相似於正常的new和delete,這種方式對於不頻繁分配,而且一次分配大塊內存的使用狀況是適用的,典型的容器像vector和deque。
2. 拓展分配器:
咱們繼續查看STL源碼會發現,除了默認分配器,gnu下的STL還實現了一些特殊的分配器,像__pool_alloc,__mt_alloc,array_allocator,malloc_allocator (在源碼的/c++/ext/ 目錄下)
__pool_alloc :比較出名的SGI內存池分配器,侯捷老師在STL源碼剖析中着重分析的,後面會專門加一章來進行講解
__mt_alloc : 多線程內存池分配器,具體能夠看一下該博主的連接講解,仍是比較詳細的
array_allocator : 全局內存分配,只分配不釋放,交給系統來釋放
malloc_allocator : 封裝了一下std::malloc和std::free
4. 自定義分配器 (allocator)
咱們爲何要自定義分配器,廢話,主要緣由固然是由於性能了。利用自定義分配器能夠顯著改善程序性能及分配器使用便利性。
對於默認分配器,也就是咱們常使用的new和malloc,若是遇到須要頻繁分配小塊內存對象的狀況,由於須要不停的向系統鎖要內存,那麼將使得分配過程變得很慢;還有就是致使出現過多的內存碎片;以及一些極端狀況,分配的內存過於小且數量龐大,致使分配一次內存,附帶的內存消耗反而更大,形成內存的浪費
主流提升性能的方式是建立基於內存池的分配器,每次在容器中插入刪除元素,不是分配內存,而是分配程序啓動時預先分配的大塊內存(內存池)。這種自定義分配器,經過簡單的從池中返回指向內存的指針來提供單獨的分配請求。還有就是能夠推遲實踐的內存釋放,直到內存池生命週期結束
C++之父 Bjarne stroustrup 提到,自定義分配器的三個主要應用,即內存池分配器,共享內存分配器和垃圾收集(gc)分配器
垃圾回收應該就是智能指針,本身控制資源的回收;內存池則主要負責對性能的提高;共享內存分配器則是對特殊緩存區的處理。 後續會一一分析介紹!
具體連接:
SGI 內存池分配器
智能指針
共享內存分配-hashmap
多線程分配器
2018年9月8日00:18:28