1. allocator 基本介紹
分配器(allocator))是c ++標準庫的乙個元件, 主要用來處理所有給定容器(vector,list,map等)記憶體的分配和釋放。c ++標準庫提供了預設使用的通用分配器std::allocator,但是,也可以由程式設計師自己提供自定義分配器。
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)
void destroy(pointer __p)
size_type max_size() const _glibcxx_use_noexcept
address(const_reference __x) const _glibcxx_noexcept
deallocate(pointer, size_type);
allocate(size_type __n, const void* = 0);
templatestruct rebind ;
對於上面這一段介面和變數,其中一些在其他容器的分析中,我們會經常看到,下面對於其中有疑問的點我們來解釋一下:
size_type:
為 unsigned 型別 , 表示容器中元素長度或者下標,例:vector::size_type i = 0;我們都知道 size_t 在32位和64位系統上是不一樣的,size_t已經可以解決平台差異了,那為什麼還要引入size_type,這裡我們可以理解為size_t是屬於全域性的,而size_type是跟容器相關的,是屬於stl的一套,在其他容器中也是一樣的。
difference_type:
為 signed 型別 , 表示迭代器差距, vector:: difference_type = iter1-iter2,ptrdiff_t通常用來儲存兩個指標減法操作的結果。
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)
// __p is not permitted to be a null pointer.
void
deallocate(pointer __p, size_type)
}_glibcxx_end_namespace_version
} // namespace
我們看一下分配和釋放的介面allocate和deallocate,實現上只是單純的將::operator new和::operator delete進行了一下封裝,沒用做特殊處理。
當然,如果我們不特別說明,直接在linux系統下使用標準c++的stl容器,在為容器元素分配記憶體時,使用的方式就是類似於正常的new和delete,這種方式對於不頻繁分配,並且一次分配大塊記憶體的使用情況是適用的,典型的容器像vector和deque。
2. 拓展分配器:
__pool_alloc :比較出名的sgi記憶體池分配器,侯捷老師在stl原始碼剖析中著重分析的,後面會專門加一章來進行講解
__mt_alloc : 多執行緒記憶體池分配器,具體可以看一下該博主的鏈結講解,還是比較詳細的
array_allocator : 全域性記憶體分配,只分配不釋放,交給系統來釋放
malloc_allocator : 封裝了一下std::malloc和std::free
4. 自定義分配器 (allocator)
我們為什麼要自定義分配器,廢話,主要原因當然是因為效能了。利用自定義分配器可以顯著改善程式效能及分配器使用便利性。
對於預設分配器,也就是我們常使用的new和malloc,如果遇到需要頻繁分配小塊記憶體物件的情況,因為需要不停的向系統鎖要記憶體,那麼將使得分配過程變得很慢;還有就是導致出現過多的記憶體碎片;以及一些極端情況,分配的記憶體過於小且數量龐大,導致分配一次記憶體,附帶的記憶體消耗反而更大,造成記憶體的浪費
主流提高效能的方式是建立基於記憶體池的分配器,每次在容器中插入刪除元素,不是分配記憶體,而是分配程式啟動時預先分配的大塊記憶體(記憶體池)。這種自定義分配器,通過簡單的從池中返回指向記憶體的指標來提供單獨的分配請求。還有就是可以推遲實踐的記憶體釋放,直到記憶體池生命週期結束
c++之父 bjarne stroustrup 提到,自定義分配器的三個主要應用,即記憶體池分配器,共享記憶體分配器和垃圾收集(gc)分配器
垃圾**應該就是智慧型指標,自己控制資源的**;記憶體池則主要負責對效能的提公升;共享記憶體分配器則是對特殊快取區的處理。 後續會一一分析介紹!
sgi 記憶體池分配器
智慧型指標
共享記憶體分配-hashmap
多執行緒分配器
2023年9月8日00:18:28
《STL原始碼剖析》學習 六大元件
stl 提供了六大元件,分別為 容器 演算法 迭代器 仿函式 介面卡和配置器。容器通過配置器取得資料儲存空間,演算法通過迭代器訪問容器的內容,仿函式可以協助演算法完成不同的策略,配接器可以修飾或者巢狀仿函式。下面分別簡單介紹 1.容器 container 各種資料結構 根據資料排列方式分為序列式和關...
STL原始碼解析1 六大元件關係
一.stl六大元件介紹 stl就是 容器類 演算法實現 迭代器 配接器 仿函式 配置器 容器通過配置器取得資料儲存空間,演算法通過迭代器訪問容器內容,仿函式可以協助演算法完成不同的策略變化,配接器可以修飾或套界仿函式 1.容器 stl容器包含兩種 序列式容器主要有vector list deque,...
STL六大元件
stl提供六大元件,彼此可以組合套用。1 容器 containers 各種資料結構。如vector,list,deque,set,map,用來存放資料。容器又可以分為順序容器和關聯容器.順序容器 vector,list,deque,stack,queue,heap,priority queue,sl...