日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

浅析STL allocator

發布時間:2023/12/1 综合教程 36 生活家
生活随笔 收集整理的這篇文章主要介紹了 浅析STL allocator 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  一般而言,我們習慣的 C++ 內存配置操作和釋放操作是這樣的:

1 class FOO{};
2 FOO *pf = new FOO;    
3 delete pf;

  我們看其中第二行和第三行,雖然都是只有一句,當是都完成了兩個動作。但你 new 一個對象的時候兩個動作是:先調用::operator new 分配一個對象大小的內存,然后在這個內存上調用FOO::FOO()構造對象。同樣,當你 delete 一個對象的時候兩個動作是:先調用FOO::~FOO()?析構掉對象,再調用::operator delete將對象所處的內存釋放。為了精密分工,STL 將allocator決定將這兩個階段分開。分別用 4 個函數來實現:

  1.內存的配置:alloc::allocate();

  2.對象的構造:::construct();

  3.對象的析構:::destroy();

  4.內存的釋放:alloc::deallocate();

  其中的?construct() 和?destroy()定義在 STL的庫文件中,源代碼如下:

 1 template <class T>
 2 inline void destroy(T* pointer) {
 3     pointer->~T();                               //只是做了一層包裝,將指針所指的對象析構---通過直接調用類的析構函數
 4 }
 5 
 6 template <class T1, class T2>
 7 inline void construct(T1* p, const T2& value) {
 8   new (p) T1(value);                            //用placement new在 p 所指的對象上創建一個對象,value是初始化對象的值。
 9 }
10 
11 template <class ForwardIterator>                //destory的泛化版,接受兩個迭代器為參數
12 inline void destroy(ForwardIterator first, ForwardIterator last) {
13   __destroy(first, last, value_type(first));    //調用內置的 __destory(),value_type()萃取迭代器所指元素的型別
14 }
15 
16 template <class ForwardIterator, class T>
17 inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {
18   typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
19   __destroy_aux(first, last, trivial_destructor());        //trival_destructor()相當于用來判斷迭代器所指型別是否有 trival destructor
20 }
21 
22 
23 template <class ForwardIterator>
24 inline void                                                //如果無 trival destructor ,那就要調用destroy()函數對兩個迭代器之間的對象元素進行一個個析構
25 __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
26   for ( ; first < last; ++first)
27     destroy(&*first);
28 }
29 
30 template <class ForwardIterator>                        //如果有 trival destructor ,則什么也不用做。這更省時間
31 inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}
32 
33 inline void destroy(char*, char*) {}          //針對 char * 的特化版
34 inline void destroy(wchar_t*, wchar_t*) {}    //針對 wchar_t*的特化版

  看到上面這么多代碼,大家肯定覺得 construct() 和 destroy() 函數很復雜。其實不然,我們看到construct()函數只有幾行代碼。而 destroy() 稍微多點。但是這么做都是為了提高銷毀對象時的效率。為什么要判斷迭代器所指型別是否有 trival destructor,然后分別調用不同的執行函數?因為當你要銷毀的對象很多的時候,而這樣對象的型別的destructor 都是 trival 的。如果都是用__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)來進行銷毀的話很費時間,因為沒必要那樣做。而當你對象的destructor 都是 non-trival 的時候,你又必須要用__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)來析構。所以,我們要判斷出對象型別的destructor 是否為 trival,然后調用不同的__destroy_aux。

  說完 construct() 和 destory() ,我們來說說?alloc::allocate() 和?alloc::deallocate(),其源代碼在 <stl_alloc.h>中。stl_alloc.h中代碼設計的原則如下:

  1.向 system heap 要求空間

  2.考慮多線程狀態

  3.考慮內存不足時的應變措施

  4.考慮過多“小型區塊”可能造成的內存碎片問題。

  stl_alloc.h中的代碼相當復雜,不過沒關系。我們今天只看其中的allocate() 和 deallocate()。在講這兩個函數之前,我們還必須來了解一下SGI? STL(SGI限定詞是STL的一個版本,因為真正的STL有很多不同公司實現的版本,我們所討論的都是SGI版本) 配置器的工作原理:

  考慮到小型區塊可能造成內存破碎問題(即形成內存碎片),SGI STL 設計了雙層級配置器。第一層配置器直接使用malloc() 和 free().第二層配置器則視情況采用不同的策略:但配置區塊超過 128 bytes時,調用第一級配置器。當配置區塊小于 128 bytes時,采用復雜的 memory pool 方式。下面我們分別簡單的介紹一下第一級和第二級配置器:

第一級配置器 _ _malloc_alloc_template:

  由于第一級配置器的配置方法比較簡單,代碼也容易理解,我在這里全部貼出:

 1 //以下是第第一級配置器
 2 template <int inst>
 3 class __malloc_alloc_template {
 4 
 5 private:
 6 
 7 //以下函數用來處理內存不足的情況
 8 static void *oom_malloc(size_t);
 9 
10 static void *oom_realloc(void *, size_t);
11 
12 static void (* __malloc_alloc_oom_handler)();
13 
14 public:
15 
16 static void * allocate(size_t n)
17 {
18     void *result = malloc(n);                    //第一級配置器,直接使用malloc()
19     //如果內存不足,則調用內存不足處理函數oom_alloc()來申請內存
20     if (0 == result) result = oom_malloc(n);
21     return result;
22 }
23 
24 static void deallocate(void *p, size_t /* n */)
25 {
26     free(p);            //第一級配置器直接使用 free()
27 }
28 
29 static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
30 {
31     void * result = realloc(p, new_sz);            //第一級配置器直接使用realloc()
32     //當內存不足時,則調用內存不足處理函數oom_realloc()來申請內存
33     if (0 == result) result = oom_realloc(p, new_sz);
34     return result;
35 }
36 
37 //設置自定義的out-of-memory handle就像set_new_handle()函數
38 static void (* set_malloc_handler(void (*f)()))()
39 {
40     void (* old)() = __malloc_alloc_oom_handler;
41     __malloc_alloc_oom_handler = f;
42     return(old);
43 }
44 };
45 
46 template <int inst>    
47 void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;  //內存處理函數指針為空,等待客戶端賦值
48 
49 template <int inst>
50 void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
51 {
52     void (* my_malloc_handler)();
53     void *result;
54 
55     for (;;) {                                                     //死循環
56         my_malloc_handler = __malloc_alloc_oom_handler;            //設定自己的oom(out of memory)處理函數
57         if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }         //如果沒有設定自己的oom處理函數,毫不客氣的拋出異常
58         (*my_malloc_handler)();                                    //設定了就調用oom處理函數
59         result = malloc(n);                                        //再次嘗試申請
60         if (result) return(result);
61     }
62 }
63 
64 template <int inst>
65 void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
66 {
67     void (* my_malloc_handler)();
68     void *result;
69 
70     for (;;) {
71         my_malloc_handler = __malloc_alloc_oom_handler;
72         if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }    //如果自己沒有定義oom處理函數,則編譯器毫不客氣的拋出異常
73         (*my_malloc_handler)();                                //執行自定義的oom處理函數
74         result = realloc(p, n);                                //重新分配空間
75         if (result) return(result);                            //如果分配到了,返回指向內存的指針
76     }
77 }

  上面代碼看似繁雜,其實流程是這樣的:

  1.我們通過allocate()申請內存,通過deallocate()來釋放內存,通過reallocate()重新分配內存。

  2.當allocate()或reallocate()分配內存不足時會調用oom_malloc()或oom_remalloc()來處理。

  3.當oom_malloc() 或 oom_remalloc()還是沒能分配到申請的內存時,會轉如下兩步中的一步:

    a).調用用戶自定義的內存分配不足處理函數(這個函數通過set_malloc_handler() 來設定),然后繼續申請內存!

    b).如果用戶未定義內存分配不足處理函數,程序就會拋出bad_alloc異常或利用exit(1)終止程序。

  看完這個流程,再看看上面的代碼就會容易理解多了!

第二級配置器 _ _default_alloc_template:

  第二級配置器的代碼很多,這里我們只貼出其中的 allocate() 和 dellocate()函數的實現和工作流程(參考侯捷先生的《STL源碼剖析》),而在看函數實現代碼之前,我大致的描述一下第二層配置器配置內存的機制。

  我們之前說過,當申請的內存大于 128 bytes時就調用第一層配置器。當申請的內存小于 128bytes時才會調用第二層配置器。第二層配置器如何維護128bytes一下內存的配置呢? SGI 第二層配置器定義了一個 free-lists,這個free-list是一個數組,如下圖:

  

  這數組的元素都是指針,用來指向16個鏈表的表頭。這16個鏈表上面掛的都是可以用的內存塊。只是不同鏈表中元素的內存塊大小不一樣,16個鏈表上分別掛著大小為

   8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128 bytes的小額區塊,圖如下:

  ?

  就是這樣,現在我們來看allocate()代碼:

 static void * allocate(size_t n){obj * __VOLATILE * my_free_list;obj * __RESTRICT result;//要申請的空間大于128bytes就調用第一級配置if (n > (size_t) __MAX_BYTES) {return(malloc_alloc::allocate(n));}//尋找 16 個free lists中恰當的一個my_free_list = free_list + FREELIST_INDEX(n);result = *my_free_list;if (result == 0) {//沒找到可用的free list,準備新填充free listvoid *r = refill(ROUND_UP(n));return r;}*my_free_list = result -> free_list_link;return (result);};

  其中有兩個函數我來提一下,一個是ROUND_UP(),這個是將要申請的內存字節數上調為8的倍數。因為我們free-lists中掛的內存塊大小都是8的倍數嘛,這樣才知道應該去找哪一個鏈表。另一個就是refill()。這個是在沒找到可用的free list的時候調用,準備填充free lists.意思是:參考上圖,假設我現在要申請大小為 56bytes 的內存空間,那么就會到free lists 的第 7 個元素所指的鏈表上去找。如果此時 #7元素所指的鏈表為空怎么辦?這個時候就要調用refill()函數向內存池申請N(一般為20個)個大小為56bytes的內存區塊,然后掛到 #7 所指的鏈表上。這樣,申請者就可以得到內存塊了。當然,這里為了避免復雜,誤導讀者我就不討論refill()函數了。allocate()過程圖如下:

  

  學過鏈表的操作的人不難理解上圖,我就不再講解。下面看deallocate(),代碼如下:

 1 static void deallocate(void *p, size_t n)
 2 {
 3     obj *q = (obj *)p;
 4     obj * __VOLATILE * my_free_list;
 5 
 6     //如果要釋放的字節數大于128,則調第一級配置器
 7     if (n > (size_t) __MAX_BYTES) {
 8         malloc_alloc::deallocate(p, n);
 9         return;
10     }
11     //尋找對應的位置
12     my_free_list = free_list + FREELIST_INDEX(n);
13     //以下兩步將待釋放的塊加到鏈表上
14     q -> free_list_link = *my_free_list;    
15     *my_free_list = q;
16 }

  deallocate()函數釋放內存的步驟如下圖:


  其實這就是一個鏈表的插入操作,也很簡單。不再贅述!上面忘了給鏈表結點的結構體定義了,如下:

union obj{union obj * free_list_link;char client_date[1]; 
};

  至此,SGI STL的對象的構造與析構、內存的分配與釋放就介紹完畢了。

?

轉載于:https://www.cnblogs.com/zhuwbox/p/3699977.html

總結

以上是生活随笔為你收集整理的浅析STL allocator的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产一卡在线 | 中文字幕无线码 | 国产色视频一区二区三区qq号 | 国产91精品久久久久久久 | 你懂的成人| www.com国产| 天堂资源在线播放 | 国产污在线观看 | 欧美一区二区三区久久妖精 | 欧美一二三区 | 黄色大片网站在线观看 | 女主播在线观看 | 男生舔女生的屁股 | 夜夜草天天草 | 四虎在线免费播放 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 秒拍福利视频 | 在线观看一二区 | av手机免费看 | 国产成人不卡 | 四虎影视免费永久大全 | 黄色av一级片 | 国产五月天婷婷 | 搡老熟女老女人一区二区 | 69精品 | 在线视频这里只有精品 | 亚洲综合久久av | 欧美激情h| 国产九色在线播放九色 | 亚洲国产成人精品女人久久久 | 亚洲视频一二三 | 精品国产欧美一区二区三区成人 | xxxx少妇| 日本免费a级片 | 毛片哪里看 | 亚洲成人三区 | 午夜网址| 五月婷婷丁香在线 | 欧美偷拍亚洲 | 青青草精品 | 成年人在线观看视频网站 | 曰本不卡视频 | 蜜桃一二三区 | 亚洲香蕉在线视频 | 91网站在线观看视频 | 国产高清一区二区三区四区 | 一区二区三区精品久久久 | 性生交大片免费看狂欲 | 激情另类小说 | 亚洲高清在线视频 | 少妇大叫太粗太大爽一区二区 | 欧美激情视频在线 | 欧美爽爽爽 | 亚洲伊人色 | 国产精品手机在线观看 | 在线伊人 | 成人性生交免费看 | 玖玖爱这里只有精品 | 精品人妻无码一区 | 蜜桃做爰免费网站 | 精品视频在线观看免费 | 91精品久久久久久综合五月天 | 国产一区二区三区视频播放 | 日韩视频免费在线观看 | 69xxx国产 | 精品人人妻人人澡人人爽牛牛 | 九色视频网站 | 91精品婷婷国产综合久久竹菊 | 欧美一二三视频 | 国模精品一区二区三区 | 亚洲4区| 国产精品亚洲二区在线观看 | 6080午夜 | 国产欧美a| 日日干日日射 | 男人的天堂黄色 | 亚洲综合中文 | 黄色aaa毛片 | 国产精品后入内射日本在线观看 | 免费在线看污 | 91精产国品一二三区在线观看 | 成人乱人乱一区二区三区 | 欧美一级淫片免费视频魅影视频 | 成人在线视频免费观看 | 欧美一区二区三区激情视频 | 亚色av | 欧美一区二区国产 | 伊人毛片| 成人免费视频一区二区三区 | 风流还珠之乱淫h文 | 日本乱大交xxxx公交车 | 韩国毛片一区二区三区 | 婷婷丁香九月 | 国产女主播喷水高潮网红在线 | 国产乱子伦精品 | 玩弄白嫩少妇xxxxx性 | 欧美视频自拍偷拍 | 日韩在线一区二区三区四区 | 欧美a级片在线观看 |