1. 程式人生 > >SGI STL 的記憶體管理

SGI STL 的記憶體管理

1. 前言

在分析完 nginx 的記憶體池之後,也想了解一下 C++ 的記憶體管理,於是就很自然得想到 STL。STL 是一個重量級的作品,據說當時的出現,完全可以說得上是一個劃時代意義的作品。泛型、資料結構和演算法的分離、底耦合、高複用… 啊,廢話不多說了,再說下去讓人感覺像王婆賣瓜了。

啊,還忘了得加上兩位 STL 大師的名字來聊表我的敬意了。泛型大牛 Alexander  Stepanov 和 Meng Lee(李夢 — 讓人浮想的名字啊)。

2. SLT 記憶體的分配

以一個簡單的例子開始。

1234567891011121314151617181920212223 #include <vector>#include <algorithm>using namespacestd;voidprint(intelem){cout<<elem<<' ';}intmain(){vector<int>vec;for(inti=0;i!=10;++i)vec.push_back(i);for_each(vec.begin(),vec.end(),print)
;//請允許我賣弄一點點小特性cout<<endl;return0;}

我們想知道的時候, 當 vec 宣告的時候和 push_back 的時候,是怎麼分配的。

其實對於一個標準的 STL 容器,當 Vetor<int> vec 的真實語句應該是 vetor<int, allocator<int>>vec,allocator 是一個標準的配置器,其作用就是為各個容器管理記憶體。這裡需要注意的是在 SGI STL 中,有兩個配置器:allocator(標準的) 和 alloc(自己實現的,非常經典,這篇文章的主要目的就是為了分析它)。

3. 一個標準的配置器

要寫一個配置器並不是很難,最重要的問題是如何分配和回收記憶體。下面看下一個標準(也許只能稱為典型)的配置器的實現:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 #include <new>// for new#include <cstddef> //  size_t#include <climits> // for unit_max#include <iostream> // for cerrusing namespacestd;namespaceSLD{template<classT>classallocator{public:typedefTvalue_type;typedefT*pointer;typedefconstT*const_pointer;typedefT&reference;typedefconstT&const_reference;typedefsize_t size_type;typedefptrdiff_t difference_type;template<classU>structrebind{typedefallocator<U>other;};//申請記憶體pointer allocate(size_typen,constvoid*hint=0){T*tmp=(T*)(::operator new((size_t)(n *sizeof(T))));//operator new 和new operator是不同的if(!tmp)cerr<<"out of memory"<<endl;returntmp;}//釋放記憶體voiddeallocate(pointerp){::operator delete(p);}//構造voidconstruct(pointerp,constT&value){new(p)T1(value);}//析構voiddestroy(pointerp){p->~T();}//取地址pointer address(referencex){return(pointer)&x;}const_pointer const_address(const_referencex){return(const_pointer)&x;}size_type max_size()const{returnsize_type(UINT_MAX/sizeof(T));}};}

注:程式碼有比較大的改動,因為主要是為了理解。

在使用的時候, 只需這樣 vector<int, SLD::allocator<int>>vec; 即可。vetor 便會自動呼叫我們的配置器分配記憶體了。要自己寫個配置器完全可以以這個類為模板。 而需要做的工作便是寫下自己的 allocate 和 deallocate 即可。

其實 SGI 的 allocator 就是這樣直接呼叫 operator new 和::operator delete 實現的,不過這樣做的話效率就很差了。

4. SGI STL 中的 alloc

4.1 SGI 中的記憶體管理

SGI STL 預設的介面卡是 alloc,所以我們在宣告一個 vector 的時候實際上是這樣的 vetor<int, alloc<int>>vec. 這個配置器寫得非常經典,下面就來慢慢分析它。

在我們敲下如下程式碼:

CSld* sld = new CSld;的時候其實幹了兩件事情:

  1. 呼叫::operator new 申請一塊記憶體(就是 malloc 了)
  2. 呼叫了 CSld::CSld();

而在 SGI 中, 其記憶體分配把這兩步獨立出了兩個函式:allocate 申請記憶體, construct 呼叫建構函式。他們分別在 <stl_alloc.h>, <stl_construct.h> 中。

SGI 的記憶體管理比上面所說的更復雜一些, 首先看一些 SGI 記憶體管理的幾個主要檔案,如下圖所示:

SGI Memory_thumb

<圖 1. SGI  記憶體管理>

在 stl_construct.h 中定義了兩個全域性函式 construct() 和 destroy() 來管理構造和析構。在 stl_allo.h 中定義了 5 個配置器, 我們現在關心的是 malloc_alloc_template(一級)和 default_alloc_template(二級)。

在 SGI 中,如果用了一級配置器,便是直接使用了malloc() 和 free() 函式,而如果使用了二級介面卡,則如果所申請的記憶體區域大於 128b,直接使用一級介面卡,否則,使用二級介面卡。而 stl_uninitialized.h 中,則定義了一下全域性函式來進行大塊記憶體的申請和複製。

是不是和 nginx 中的記憶體池很相似啊,不過複雜多了。

4.2 一級配置器:__malloc_alloc_template

上面說過, SGI STL 中, 如果申請的記憶體區域大於 128B 的時候,就會呼叫一級介面卡,而一級介面卡的呼叫也是非常簡單的, 直接用 malloc 申請記憶體,用 free 釋放記憶體。

可也看下如下的程式碼:

12345678910111213141516171819202122232425262728293031323334353637383940 class__malloc_alloc_template{private:// oom = out of memroy,當記憶體不足的時候,我要用下面這兩個函式staticvoid*_S_oom_malloc(size_t);staticvoid*_S_oom_realloc(void*,size_t);public://申請記憶體staticvoid*allocate(size_t __n){void*__result=malloc(__n);//如果不足,我有不足的處理方法if(0==__result)__result=_S_oom_malloc(__n);return__result;}//直接釋放掉了staticvoiddeallocate(void*__p,size_t/* __n */){free(__p);}//重新分配記憶體staticvoid*reallocate(void*__p,size_t/* old_sz */,size_t __new_sz){void*__result=realloc(__p,__new_sz);if(0==__result)__result=_S_oom_realloc(__p,__new_sz);return__result;}//模擬C++的 set_new_handler,函式,//為什麼要模擬,因為現在用的是C的記憶體管理函式。staticvoid(*__set_malloc_handler(void(*__f)()))(){void(*__old)()=__malloc_alloc_oom_handler;__malloc_alloc_oom_handler=__f;return(__old);}};

好了, 很簡單把,只是對 malloc,free, realloc 簡單的封裝。

4.3 二級配置器:__default_alloc_template

按上文所說的,SGI 的 __default_alloc_template 就是一個記憶體池了。

我們首先來看一下它的程式碼:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 template<boolthreads,intinst>class__default_alloc_template{private:// Really we should use static const int x = N// instead of enum { x = N }, but few compilers accept the former.enum{_ALIGN=8};//小塊區域的上界enum{_MAX_BYTES=128};//小塊區域的下降enum{_NFREELISTS=16};// _MAX_BYTES/_ALIGN,有多少個區域/*SGI 為了方便記憶體管理, 把128B 分成16*8 的塊*///將Byte調到8的倍數staticsize_t_S_round_up(size_t __bytes){return(((__bytes)+(size_t)_ALIGN-1)&~((size_t)_ALIGN-1));}//管理記憶體的連結串列,待會會詳細分析這個union_Obj{union _Obj*_M_free_list_link;char_M_client_data[1];/* The client sees this.        */};private://聲明瞭16個 free_list, 注意 _S_free_list是成員變數static_Obj*__STL_VOLATILE _S_free_list[_NFREELISTS];//同了第幾個free_list, 即_S_free_list[n],當然這裡是更具區域大小來計算的staticsize_t _S_freelist_index(size_t __bytes){return(((__bytes)+(size_t)_ALIGN-1)/(size_t)_ALIGN-1);}// Returns an object of size __n, and optionally adds to size __n free list.

相關推薦

[SGI STL]空間配置器--記憶體管理

[SGI STL]系列文章前言        廢話不多說,讀侯捷的SGI STL原始碼分析目的有三個: 1,接觸c++不久就開始跟STL打交道,一直有個好奇心,這麼強大的庫到底是誰、咋實現的?; 2,不熟悉實現就用不好STL,所以想更好的應用STL,就有必要一探其底層驅

SGI STL記憶體管理

1. 前言 在分析完 nginx 的記憶體池之後,也想了解一下 C++ 的記憶體管理,於是就很自然得想到 STL。STL 是一個重量級的作品,據說當時的出現,完全可以說得上是一個劃時代意義的作品。泛型、資料結構和演算法的分離、底耦合、高複用… 啊,廢話不多說了,再說下去讓人感覺像王婆賣瓜了。 啊,還忘了得加

動態記憶體管理allocator類C++ STL標準模板庫vector實現

//vector.h #ifndef NSTL_VECTOR_H_ #define NSTL_VECTOR_H_ #include <memory> #include <string> namespace nstl { class vector { public

STL容器的記憶體管理

class Unit { public: Unit(); Unit(int id); ~Unit(); private: int id = -1; }; Unit::Unit() { }

研究了一下SGI STL記憶體演算法

原理在STL原始碼剖析中已經有闡述,這裡簡單的說一下,該記憶體池採用HASH-LIST資料結構管理資料,分配一塊記憶體時,如果所要求的記憶體超過了某個數量就直接呼叫malloc分配記憶體, 否則首先進行資料對齊,根據這個對齊的結果得到所在的HASH表,在該HASH-LIST中查詢時候存在可用的節點,如

SGI STL內存配置器存在內存泄漏嗎?

析構 溫故而知新 溫故 由於 默認 文件路徑 htm .com 成員 閱讀了SGI的源碼後對STL很是膜拜,很高質量的源碼,從中學到了很多。溫故而知新!下文中所有STL如無特殊說明均指SGI版本實現。 STL 內存配置器 STL對內存管理最核心部分我覺得是其將C++對象創建

SGI STL內存配置器(一):內存泄漏?

分解 產生 for void 客戶端 lin call free 創建過程 閱讀了Alexander大神的SGI STL源碼,膜拜,很高質量的源碼,獲益匪淺。溫故而知新!下文中所有STL如無特殊說明均指SGI版本實現。 STL 內存配置器 STL對內存管理最核心部分我覺得是

第四節:FreeRTOS 記憶體管理

目錄 記憶體管理的介紹 記憶體碎片 Heap_1-5記憶體分配的區別 Heap_1:適用於一旦建立好記憶體,就不刪除的任務。       (本質是分配的大陣列做記憶體堆.) Heap_2:適用於重複分配和刪除具有相同堆疊空間任務。(本質是分配的大

Objective-C高階程式設計:iOS與OS X多執行緒和記憶體管理

這篇文章主要給大家講解一下GCD的平時不太常用的API,以及文末會貼出GCD定時器的一個小例子。 需要學習的朋友可以通過網盤免費下載pdf版 (先點選普通下載-----再選擇普通使用者就能免費下載了)http://putpan.com/fs/cy1i1beebn7s0h4u9/ 1.G

找工作筆試面試那些事兒(3)---記憶體管理那些事

作者:寒小陽 時間:2013年8月。 出處:http://blog.csdn.net/han_xiaoyang/article/details/10676931。 宣告:版權所有,轉載請註明出處,謝謝。   七、記憶體管理        

記憶體管理+記憶體佈局

記憶體管理 8.1 作用域 C語言變數的作用域分為: l  程式碼塊作用域(程式碼塊是{}之間的一段程式碼) l  函式作用域 l  檔案作用域 8.1.1 區域性變數 區域性變數也叫auto自動變數(auto可寫可不寫),一般情況下程式碼塊{}內部定義的變數都是自

Linux記憶體管理(最透徹的一篇)

摘要:本章首先以應用程式開發者的角度審視Linux的程序記憶體管理,在此基礎上逐步深入到核心中討論系統實體記憶體管理和核心記憶體的使用方法。力求從外到內、水到渠成地引導網友分析Linux的記憶體管理與使用。在本章最後,我們給出一個記憶體對映的例項,幫助網友們理解核心記憶體管理與使用者記憶體管理之

[讀書筆記]iOS與OS X多執行緒和記憶體管理 [GCD部分]

3.2 GCD的API 蘋果對GCD的說明:開發者要做的只是定義想執行的任務並追加到適當的Dispatch Queue中。 “Dispatch Queue”是執行處理的等待佇列。通過dispatch_async函式等API,在Block

c++之動態記憶體管理

1.new/delete 和operator new/operator delete和malloc/free的關係 ①new呼叫operator new分配空間②new呼叫建構函式初始化物件。③delete呼叫解構函式清理物件 ④delete呼叫operator delete釋放空間 ⑤ope

Java_記憶體管理和繼承

Java 記憶體管理 例項 public class Test { public static void main(String[] args) { // TODO Auto-generated method

Android 記憶體管理記錄

專案中用到大量大圖,造成快速切換Activity後記憶體不足,如登入介面用到3M高清大圖,裝置選擇用到5張大圖背景疊加效果,主介面用到了5張遮罩大圖,設定介面總的子activity中也有大圖出現。 啟動Splash——裝置選擇介面(保留棧低,不finish,但會把背景圖片回收)-->主介面-

AMS之記憶體管理

原文地址:http://www.jianshu.com/p/72045d243b44 參考資料地址:http://book.51cto.com/art/201109/291375.htm 記憶體管理包括兩個部分 1.當應用程式關閉後,後臺對應的程序並沒有真正退出,以便下次啟動時能夠

三、Java虛擬機器自動記憶體管理機制、物件建立及記憶體分配

  1、物件是如何建立: 步驟:    (1)、虛擬機器遇到new <類名>的指令---->根據new的引數是否在常量池中定位一個類的符號引用    (2)、檢測該符號引用代表的類是否已經被載入、解析、和初始化。(如果沒有則

第七章—記憶體管理【計算機作業系統】

7.1 記憶體管理需要滿足哪些需求? 重定位、保護、共享、邏輯組織和物理組織。 7.2 為什麼需要重定位程序的能力? 通常情況下,並不能事先知道在某個程式執行期間會有哪個程式駐留在主存中。此外還希望通過提供一個巨大的就緒程序池,能夠把活動程序換入和換出主存,以便使處理器的利用率

【c/c++】記憶體管理

文章目錄 1.c/c++記憶體分配 2.C語言中動態記憶體管理方式malloc/calloc/realloc與free 3.C++記憶體管理方式 3.1new/delete操作內建型別 3.2new和delete操