青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

SGI STL中默認Allocator為何變?yōu)閚ew_allocator?

peakflys原創(chuàng)作品,轉載請保留原作者和源鏈接
   項目中和自己代碼中大量使用了STL的容器,平時也沒怎么關注alloc的具體實現(xiàn)細節(jié),主觀認識上還停留在侯捷大師的《STL源碼剖析》中的講解。
   以下為書中摘錄截圖:詳見書中2.2.4節(jié)內(nèi)容

前段時間項目中出了一個內(nèi)存問題,在追查問題的過程中查看了對應的源碼(版本為libstdc++-devel-4.1.2)
源碼文件c++allocator.h中定義了默認的Alloc:#ifndef _CXX_ALLOCATOR_H
#define _CXX_ALLOCATOR_H 1

// Define new_allocator as the base class to std::allocator.
#include <ext/new_allocator.h>
#define __glibcxx_base_allocator  __gnu_cxx::new_allocator

#endif
查看new_allocator.h文件,發(fā)現(xiàn)new_allocator僅僅是對operator new和operator delete的簡單封裝(感興趣的朋友可自行查看)。
眾所周知libstdc++中STL的大部分實現(xiàn)是取自SGI的STL,而《STL源碼剖析》的源碼是Cygnus C++ 2.91則是SGI STL的早期版本,下載源碼看了一下allocator的實現(xiàn)確實如書中所言。
不知道從哪個版本起,SGI的STL把默認的Alloc替換成了new_allocator,有興趣的同學可以查一下。
知道結果后,可能很多人和我一樣都不禁要問:Why?
以下是兩個版本的源碼實現(xiàn):
1、new_allocator
      // 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 (__builtin_expect(__n > this->max_size(), false))
      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); }
2、__pool_alloc
  template<typename _Tp>
    _Tp*
    __pool_alloc<_Tp>::allocate(size_type __n, const void*)
    {
      pointer __ret = 0;
      if (__builtin_expect(__n != 0, true))
    {
      if (__builtin_expect(__n > this->max_size(), false))
        std::__throw_bad_alloc();

      // If there is a race through here, assume answer from getenv
      
// will resolve in same direction.  Inspired by techniques
      
// to efficiently support threading found in basic_string.h.
      if (_S_force_new == 0)
        {
          if (getenv("GLIBCXX_FORCE_NEW"))
        __atomic_add(&_S_force_new, 1);
          else
        __atomic_add(&_S_force_new, -1);
        }

      const size_t __bytes = __n * sizeof(_Tp);
      if (__bytes > size_t(_S_max_bytes) || _S_force_new == 1)
        __ret = static_cast<_Tp*>(::operator new(__bytes));
      else
        {
          _Obj* volatile* __free_list = _M_get_free_list(__bytes);

          lock sentry(_M_get_mutex());
          _Obj* __restrict__ __result = *__free_list;
          if (__builtin_expect(__result == 0, 0))
        __ret = static_cast<_Tp*>(_M_refill(_M_round_up(__bytes)));
          else
        {
          *__free_list = __result->_M_free_list_link;
          __ret = reinterpret_cast<_Tp*>(__result);
        }
          if (__builtin_expect(__ret == 0, 0))
        std::__throw_bad_alloc();
        }
    }
      return __ret;
    }
  template<typename _Tp>
    void
    __pool_alloc<_Tp>::deallocate(pointer __p, size_type __n)
    {
      if (__builtin_expect(__n != 0 && __p != 0, true))
    {
      const size_t __bytes = __n * sizeof(_Tp);
      if (__bytes > static_cast<size_t>(_S_max_bytes) || _S_force_new == 1)
        ::operator delete(__p);
      else
        {
          _Obj* volatile* __free_list = _M_get_free_list(__bytes);
          _Obj* __q = reinterpret_cast<_Obj*>(__p);

          lock sentry(_M_get_mutex());
          __q ->_M_free_list_link = *__free_list;
          *__free_list = __q;
        }
    }
    }
從源碼中可以看出new_allocator基本就沒有什么實現(xiàn),僅僅是對operator new和operator delete的封裝,而__pool_alloc的實現(xiàn)基本和《STL源碼剖析》中一樣,所不同的是加入了多線程的支持和強制operator new的判斷。
無論從源碼來看,還是實際的測試(后續(xù)會附上我的測試版本),都可以看出__pool_alloc比new_allocator更勝一籌。

同很多人討論都不得其解,網(wǎng)上也很少有關注這個問題的文章和討論,倒是libstdc++的官網(wǎng)文檔有這么一段:
(peakflys注:文檔地址:https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#allocator.default)
從文檔的意思來看,選擇new_allocator是基于大量測試,不幸的是文檔中鏈接的測試例子均無法訪問到……不過既然他們說基于測試得出的結果,我就隨手寫了一個自己的例子:
#include <map>
#include <vector>
#ifdef _POOL
#include <ext/pool_allocator.h>
#endif

static const unsigned int Count = 1000000;

using namespace std;

struct Data
{
    int a;
    double b;
};

int main()
{
#ifdef _POOL
    map<int, Data, less<int>, __gnu_cxx::__pool_alloc<pair<int, Data> > > mi;
    vector<Data, __gnu_cxx::__pool_alloc<Data> > vi;
#else
    map<int, Data> mi;
    vector<Data> vi;
#endif

    for(int i = 0; i < Count; ++i)
    {
        Data d;
        d.a = i;
        d.b = i * i;
        mi[i] = d;
        vi.push_back(d);
    }
    mi.clear();
#ifdef _POOL
    vector<Data, __gnu_cxx::__pool_alloc<Data> >().swap(vi);
#else
    vector<Data>().swap(vi);
#endif
    for(int i = 0; i < Count; ++i)
    {
        Data d;
        d.a = i;
        d.b = i * i;
        mi[i] = d;
        vi.push_back(d);
    }
    return 0;
}
因為當數(shù)據(jù)大于128K時,__pool_alloc同new_allocator一樣直接調(diào)用operator,所以例子中構造出的Data小于128K,來模擬兩個分配器的不同。同時如libstdc++官網(wǎng)中說的,我們同時使用了sequence容器vector和associate容器map。
例子中模擬了兩種類型容器的插入-刪除-插入的過程,同時里面包含了元素的構造、析構以及內(nèi)存的分配和回收。
以下是在我本地機器上運行的結果:
1、-O0的版本:

2、-O2的版本:

多線程的測試例子我就不貼了,測試結果大致和上面相同,大家可以自行測試。
從多次運行的結果來看__pool_alloc的性能始終是優(yōu)于new_allocator的。
又回到那個問題,為什么SGI STL的官方把默認的Alloc從__pool_alloc變?yōu)閚ew_allocator。
本篇文章不能給大家一個答案,官方網(wǎng)站上也未看到解釋,自己唯一可能的猜測是
1、__pool_alloc不利于使用者自定義operator new和operator delete(其實這條理由又被我自己推翻了,因為通過源碼可以知道置位_S_force_new即可解決)
2、malloc性能的提升以及硬件的更新導致使用默認的operator new即可。

如果大家有更好,更權威的答案請告訴我(peakflys@gmail.com)或者留言,謝謝。
                                                                  by peakflys 16:49:49 Wednesday, January 14, 2015

posted on 2015-01-14 16:50 peakflys 閱讀(4451) 評論(8)  編輯 收藏 引用 所屬分類: C++

評論

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator? 2015-01-15 00:12 egmkang

跟硬件沒關系,malloc性能提升.因為malloc本身在thread上面就有一個pool.
而且高性能的分配器越來越多,比如tcmalloc/jemalloc,已經(jīng)沒有任何必要再提供一個pool allocator  回復  更多評論   

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator? 2015-01-15 09:12 蘋果汁

樓主好學 贊一個  回復  更多評論   

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator?[未登錄] 2015-01-15 13:01 chipset

pool不拼接內(nèi)存,一塊大內(nèi)存被分割成很多相等的小塊,此時調(diào)用分配一塊較大內(nèi)存可能失敗,不是因為內(nèi)存不夠用,而是因為全是分割成小碎塊不拼接導致的。這是Pool的致命傷。再者Pool的效率也高不到哪里,以不拼接小塊換速度的做法不值得提倡。  回復  更多評論   

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator? 2015-01-15 17:42 xxoo

樓上的,內(nèi)存池的作用不就是這個嗎?你申請一塊內(nèi)存,可以做到物理不連續(xù)?  回復  更多評論   

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator? 2015-01-15 19:23 peakflys

如果我沒記錯的話malloc自始至終都有自己的一套pool策略,所以我所說的malloc性能提升并非指的這個。
不過第三方穩(wěn)定高效的allocator實現(xiàn)可能是標準庫作者放棄pool的一個原因@egmkang
  回復  更多評論   

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator? 2015-01-15 19:31 peakflys

說的不錯,pool的方式存在的問題是挺多。不過對于pool的效率高不到哪去的觀點我不敢認同,針對大量小數(shù)據(jù)的分配,有時候還必須得使用pool的方式,不然ptmalloc、tcmalloc、jemalloc等不會維護復雜的內(nèi)存分配方式@chipset  回復  更多評論   

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator? 2015-01-20 15:24 juegoskizi

我很喜歡,很不錯的職位。  回復  更多評論   

# re: SGI STL中默認Allocator為何變?yōu)閚ew_allocator?[未登錄] 2016-03-07 14:09 JAKE

樓主,有個問題請教下:
我有個應用場景,即線程A使用obj_pool分配了一個對象obj,線程B用完obj后歸還給pool。 這里肯定會有線程同步隱患。

目前我使用兩個lockfree隊列完美解決這個問題,但很繁瑣。

我想問的是
使用tcmalloc的話,能解決我上邊所說的問題嗎?  回復  更多評論   

<2012年12月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

導航

統(tǒng)計

公告

人不淡定的時候,就愛表現(xiàn)出來,敲代碼如此,偶爾的靈感亦如此……

常用鏈接

留言簿(4)

隨筆分類

隨筆檔案

文章檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区高清在线观看| 国产综合第一页| 亚洲素人一区二区| 麻豆九一精品爱看视频在线观看免费| 国产精品外国| 亚洲图片在线观看| 亚洲精品一区二区三| 国产精品亚洲美女av网站| 麻豆av一区二区三区久久| 日韩午夜剧场| 久久久免费精品视频| 亚洲免费福利视频| 欧美视频网址| 亚洲福利电影| 久久av免费一区| 亚洲成人自拍视频| 亚洲缚视频在线观看| 亚洲另类视频| 亚洲欧美大片| 欧美一区二区三区四区视频| 欧美一区二区视频在线| 性欧美videos另类喷潮| 免费在线播放第一区高清av| 欧美日韩二区三区| 国产精品极品美女粉嫩高清在线 | 欧美jizz19性欧美| 日韩性生活视频| 亚洲综合国产| 久久一区二区三区av| 欧美精品一区二区三区在线播放 | 欧美在线二区| 欧美午夜片欧美片在线观看| 久久人人看视频| 亚洲国产精品悠悠久久琪琪| 欧美在线视频一区| 亚洲国产三级| 欧美综合77777色婷婷| 欧美视频日韩| 最新国产精品拍自在线播放| 亚洲网站在线看| 久久精品视频在线看| 亚洲人成在线播放| 这里只有精品视频| 久久久久久久综合色一本| 伊人狠狠色j香婷婷综合| 亚洲毛片在线看| 亚洲国产清纯| 久久综合国产精品台湾中文娱乐网| 国产精品你懂的在线| 亚洲美女性视频| 狼狼综合久久久久综合网| 亚洲午夜日本在线观看| 欧美区一区二| 亚洲日本欧美| 欧美一级播放| 亚洲欧美国产毛片在线| 欧美成人精品一区二区| 久久精品视频在线看| 欧美日韩亚洲综合一区| 亚洲一区二区在线免费观看| 亚洲少妇自拍| 在线成人免费观看| 欧美91大片| 欧美国产日产韩国视频| 一区二区三区日韩精品| 一区二区av| 欧美承认网站| 亚洲免费在线视频一区 二区| 亚洲精品国产精品乱码不99 | 亚洲国产精品va在线看黑人动漫| 亚洲天堂成人在线视频| 狠狠操狠狠色综合网| 亚洲高清视频在线| 国内欧美视频一区二区| 亚洲小少妇裸体bbw| 在线看国产日韩| 99国产精品久久久久久久| 国产一区二区三区的电影| 亚洲欧美视频一区| 国产精品久久久久99| 一区电影在线观看| 亚洲欧美激情视频在线观看一区二区三区 | 亚洲国产裸拍裸体视频在线观看乱了中文 | 亚洲国产成人在线| 韩国在线视频一区| av成人免费在线观看| 国产欧美日韩不卡| 亚洲国产精品免费| 久久成人羞羞网站| 亚洲人成在线观看| 欧美巨乳在线观看| 亚洲国内精品| 亚洲精品影院| 欧美va亚洲va国产综合| 亚洲精品乱码久久久久久日本蜜臀| 国产亚洲成年网址在线观看| 亚洲欧洲视频在线| 国产精品一区二区黑丝| 久久久99久久精品女同性| 亚洲成色最大综合在线| 亚洲人精品午夜| 欧美日韩一区二区在线观看| 亚洲一区亚洲二区| 一区二区三区视频在线看| 欧美久久久久久久久| 嫩草影视亚洲| 久久精品1区| 亚洲影音先锋| 女女同性精品视频| 亚洲欧美在线免费观看| 亚洲欧洲午夜| 激情久久五月| 欧美激情综合亚洲一二区| 日韩视频中文| 99亚洲一区二区| 亚洲国产黄色片| 欧美在线视频日韩| 亚洲欧美日韩国产中文| 日韩一级免费观看| 在线观看欧美日韩| 国产精品日韩专区| 欧美大片在线观看| 欧美天堂亚洲电影院在线播放| 欧美日韩一区二区在线| 欧美性淫爽ww久久久久无| 欧美www视频在线观看| 性欧美超级视频| 久久精品91久久香蕉加勒比| 亚洲精品久久久蜜桃| 美女图片一区二区| 一本久久精品一区二区| 亚洲在线免费观看| 欧美一区二粉嫩精品国产一线天| 一区二区三区 在线观看视| 亚洲精品一区二区三区蜜桃久 | 国产视频精品免费播放| 欧美日韩精品免费 | 欧美韩日一区| 久久久99爱| 国产精品视频| 日韩系列在线| 久久精品国产久精国产爱| 欧美中文在线免费| 久久成人精品| 欧美成人久久| 亚洲在线视频观看| 国产精品国产a级| 亚洲国产综合在线| 在线视频欧美日韩精品| 久久精品99国产精品| 久久久在线视频| 亚洲电影自拍| 欧美午夜一区| 午夜精品av| 91久久在线播放| 欧美一级视频| 国产日韩专区| 老司机午夜精品视频| 欧美电影在线播放| 亚洲综合色丁香婷婷六月图片| 欧美国产日本在线| 日韩亚洲一区在线播放| 亚洲九九爱视频| 欧美日韩不卡合集视频| 在线亚洲一区二区| 99re成人精品视频| 国产精品美女| 久久久久久久综合| 久久久久久黄| 在线综合欧美| 欧美一区视频在线| 亚洲国产精品123| 亚洲美女尤物影院| 国产日韩高清一区二区三区在线| 午夜视频一区| 亚洲国产精品日韩| 欧美精品自拍| 欧美mv日韩mv国产网站app| 牛牛国产精品| 国产亚洲成av人在线观看导航| 亚洲国产1区| 久久人人超碰| 亚洲视频精选| 国产精品黄视频| 中文av字幕一区| 亚洲欧美日本日韩| 精品成人免费| 亚洲网站在线| 亚洲国产精品视频一区| 亚洲精品影院在线观看| 国内精品国产成人| 亚洲成人中文| 国产精品嫩草99a| 99精品久久| 99国内精品久久久久久久软件| 欧美在线一二三| 午夜精品区一区二区三| 欧美日韩福利| 亚洲精品极品| 亚洲卡通欧美制服中文|