STL 原始碼分析六大元件 allocator

2022-08-24 06:42:09 字數 3092 閱讀 1786

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...