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

            我執(zhí)分別心

            除了自己還有誰(shuí)

            怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池

            以前在一個(gè)高性能的場(chǎng)合,需要十分頻繁的使用臨時(shí)緩存。由于所需的緩存大小我事先知道,所以我索性開(kāi)了一塊全局緩存,不要罵我土,它背后可以一個(gè)崇高的設(shè)計(jì)哲學(xué):奧坎姆的剃刀。
            不過(guò),后邊我越看越惡心,越看越想吐,于是就想實(shí)現(xiàn)一個(gè)分配和釋放都為常數(shù)時(shí)間的MemPool. 雖然內(nèi)存池是一個(gè)老得不老再老的話題,但是我并沒(méi)有找到一個(gè)能達(dá)到我要求的設(shè)計(jì)。
            雖然我對(duì)C++的任何細(xì)節(jié)都毫不知情,不過(guò)還是免為其難的寫(xiě)了一個(gè)有諸多缺陷的XMemPool。

            先說(shuō)下大致思路:
            1 POOL將分配劃分成兩種情況,小緩存分配,大緩存分配。小于4K的我把它當(dāng)成小緩存。小緩存塊BlockSize按8字節(jié)步長(zhǎng)增長(zhǎng),大塊默認(rèn)按4K步長(zhǎng)增長(zhǎng)。每種Size的塊用兩個(gè)鏈表進(jìn)行管理(free & used)。
            2 分配。要是size超過(guò)了最大能分配的大小或者池容量超過(guò)限制就直接調(diào)用系統(tǒng)分配。計(jì)算相應(yīng)塊的index(如果是調(diào)用系統(tǒng)分配的index會(huì)置為-1), 把free list第一個(gè)結(jié)點(diǎn)移到used list的第一個(gè)結(jié)點(diǎn)
            3 釋放。 如果塊的index為-1直接delete。將要釋放的塊直接移動(dòng)到free list的第一個(gè)結(jié)點(diǎn)。

            這樣的話缺點(diǎn)也是相當(dāng)明顯的:
            1 用戶(hù)必要從Block獲取緩存
            2 用戶(hù)非常有必要對(duì)緩存大小事先按需求進(jìn)行合理估計(jì)。

             1#ifndef _X_MEM_POOL_H_
             2#define _X_MEM_POOL_H_
             3
             4//! (1)alloc:O(1)
             5//! (2)free :O(1)
             6//! (3)not thread safe
             7
             8class XMemPool;
             9class XMemBlock
            10{
            11public:
            12    XMemBlock( const int& index, const size_t& size ):
            13      _index( index ),
            14      _next( 0 ),
            15      _pre( 0 ),
            16      _size( size )
            17    {
            18        _data = new char[size];
            19    }

            20    ~XMemBlock()
            21    {
            22        delete []_data;
            23    }

            24
            25public:
            26    friend class XMemPool;
            27    template<class T>
            28    T* getMem() const return (T*)_data; }
            29
            30private:
            31    const int    _index;
            32    const size_t _size;
            33    char        *_data;
            34    XMemBlock  *_next;
            35    XMemBlock  *_pre;
            36}
            ;
            37
            38const size_t S_MEM_THRE        = 4096;//4K
            39const size_t S_POOL_STEP       = 8;
            40const size_t LARGE_POOL_STEP   = 4096;//4K
            41const size_t SMAX_SUB_POOL_CAP = 128;
            42const size_t LMAX_SUB_POOL_CAP = 64;
            43
            44class XMemPool
            45{
            46public:
            47    /* 
            48    maxBlockSize 此內(nèi)存池能分配的最大的內(nèi)存
            49    maxSubPoolCapability 每個(gè)子內(nèi)存池的最大容量
            50    poolXep 相鄰子內(nèi)存池之間的BlockSize的差距,即每個(gè)子內(nèi)存池大小為poolXep的整數(shù)倍
            51
            52    這里小塊的容量,大小寫(xiě)死了的,只有大塊的可以配置
            53    */

            54    XMemPool( const size_t& maxBlockSize, const size_t& lmaxSubPoolCapability = LMAX_SUB_POOL_CAP,\
            55        const size_t& lpoolXep = LARGE_POOL_STEP );
            56    ~XMemPool();
            57public:
            58    XMemBlock *alloc( size_t size );
            59    void free( XMemBlock* block );
            60    void destroy();
            61    size_t getTotalMemSize() const return _totalMemSize; };
            62
            63private:
            64    const size_t _maxBlockSize;  //最大能分配的內(nèi)存塊
            65    const size_t _lmaxSubPoolCapability; //每種塊的最大小數(shù)(大塊)
            66    static const size_t\
            67                 _smaxSubPoolCapability = SMAX_SUB_POOL_CAP;//每種塊的最大小數(shù)(小塊)
            68    const size_t _lpoolXep; //大塊的增長(zhǎng)步長(zhǎng)
            69    static const size_t\
            70                 _spoolXep = S_POOL_STEP; //小塊的步長(zhǎng)
            71    XMemBlock **_ssubPool[2];//0:free 1:used 小塊的鏈表數(shù)組
            72    XMemBlock **_lsubPool[2];//大塊的鏈表數(shù)組
            73    size_t       _ssubPoolNum;//小塊的種類(lèi)個(gè)數(shù)
            74    size_t       _lsubPoolNum;//大塊的種類(lèi)個(gè)數(shù)
            75    size_t      *_lsubPoolSize;//每種size大塊的個(gè)數(shù)
            76    size_t      *_ssubPoolSize;//每種size小塊的個(gè)數(shù)
            77    size_t       _totalMemSize;//內(nèi)存池總?cè)萘?/span>
            78}
            ;
            79
            80#endif

             

              1XMemPool::XMemPool( const size_t& maxBlockSize, const size_t& lmaxSubPoolCapability, const size_t& lpoolXep ):\
              2_maxBlockSize( maxBlockSize ),
              3_lmaxSubPoolCapability( lmaxSubPoolCapability ),
              4_lpoolXep( lpoolXep )
              5{
              6    _ssubPoolNum = ( S_MEM_THRE + _spoolXep - 1 ) / _spoolXep;
              7    _lsubPoolNum = ( _maxBlockSize + _lpoolXep - 1 ) / _lpoolXep;
              8    _totalMemSize = 0;
              9    _ssubPoolSize = new size_t[_ssubPoolNum];
             10    _lsubPoolSize = new size_t[_lsubPoolNum];
             11    _ssubPool[0= new XMemBlock*[_ssubPoolNum];
             12    _ssubPool[1= new XMemBlock*[_ssubPoolNum];
             13    forint i = 0; i < _ssubPoolNum; i++ )
             14    {
             15        _ssubPool[0][i] = 0;
             16        _ssubPool[1][i] = 0;
             17        _ssubPoolSize[i] = 0;
             18    }

             19    _lsubPool[0= new XMemBlock*[_lsubPoolNum];
             20    _lsubPool[1= new XMemBlock*[_lsubPoolNum];
             21    forint i = 0; i < _lsubPoolNum; i++ )
             22    {
             23        _lsubPool[0][i] = 0;
             24        _lsubPool[1][i] = 0;
             25        _lsubPoolSize[i] = 0;
             26    }

             27}

             28
             29XMemBlock* XMemPool::alloc( size_t size ) //byte unit
             30{
             31    if( size <= S_MEM_THRE )
             32    {
             33        size_t idx = ( size + _spoolXep - 1 ) / _spoolXep - 1;
             34        XMemBlock *block = 0;
             35        if( _ssubPool[0][idx] )
             36        {
             37            block = _ssubPool[0][idx];
             38            _ssubPool[0][idx] = block->_next;
             39            if( _ssubPool[1][idx] )
             40                _ssubPool[1][idx]->_pre = block;
             41            block->_next = _ssubPool[1][idx];
             42            _ssubPool[1][idx] = block;
             43            _ssubPool[1][idx]->_pre = 0;
             44            return block;
             45        }

             46        else if( _ssubPoolSize[idx] < _smaxSubPoolCapability )
             47        {
             48            size_t msize = (idx + 1)*_spoolXep;
             49            _totalMemSize += msize;
             50            block = new XMemBlock( idx, msize );
             51            _ssubPoolSize[idx]++;
             52            if( _ssubPool[1][idx] )
             53                _ssubPool[1][idx]->_pre = block;
             54            block->_next = _ssubPool[1][idx];
             55            _ssubPool[1][idx] = block;
             56            return block;
             57        }

             58    }

             59    else if( size <= _maxBlockSize )
             60    {
             61        size_t idx = ( size + _lpoolXep - 1 ) / _lpoolXep - 1;
             62        XMemBlock *block = 0;
             63        if( _lsubPool[0][idx] )
             64        {
             65            block = _lsubPool[0][idx];
             66            _lsubPool[0][idx] = block->_next;
             67            if( _lsubPool[1][idx] )
             68                _lsubPool[1][idx]->_pre = block;
             69            block->_next = _lsubPool[1][idx];
             70            _lsubPool[1][idx] = block;
             71            _lsubPool[1][idx]->_pre = 0;
             72            return block;
             73        }

             74        else if( _lsubPoolSize[idx] < _lmaxSubPoolCapability )
             75        {
             76            size_t msize = (idx + 1)*_lpoolXep;
             77            _totalMemSize += msize;
             78            block = new XMemBlock( idx, msize );
             79            _lsubPoolSize[idx]++;
             80            if( _lsubPool[1][idx] )
             81                _lsubPool[1][idx]->_pre = block;
             82            block->_next = _lsubPool[1][idx];
             83            _lsubPool[1][idx] = block;
             84            return block;
             85        }

             86    }

             87
             88     return (new XMemBlock( -1, size ));
             89}

             90
             91void XMemPool::free( XMemBlock *block )
             92{
             93    if( block->_index < 0 )
             94    {
             95        delete block;
             96        return;
             97    }

             98    if( block->_size <= S_MEM_THRE )
             99    {
            100        if( block->_next )
            101            block->_next->_pre = block->_pre;
            102        if( block->_pre )
            103            block->_pre->_next = block->_next;
            104        else if!block->_next && !block->_pre )
            105            _ssubPool[1][block->_index] = 0;
            106        block->_next = _ssubPool[0][block->_index];
            107        if( _ssubPool[0][block->_index] )
            108            _ssubPool[0][block->_index]->_pre = block;
            109        _ssubPool[0][block->_index] = block;
            110    }

            111    else
            112    {
            113        if( block->_next )
            114            block->_next->_pre = block->_pre;
            115        if( block->_pre )
            116            block->_pre->_next = block->_next;
            117        else if!block->_next && !block->_pre )
            118            _lsubPool[1][block->_index] = 0;
            119        block->_next = _lsubPool[0][block->_index];
            120        if( _lsubPool[0][block->_index] )
            121            _lsubPool[0][block->_index]->_pre = block;
            122        _lsubPool[0][block->_index] = block;
            123    }

            124}

            125
            126void XMemPool::destroy()
            127{
            128    forint i = 0; i < _ssubPoolNum; i++ )
            129    {
            130        XMemBlock *block = _ssubPool[0][i], *tmp;
            131        while( block )
            132        {
            133            tmp = block->_next;
            134            delete block;
            135            block = tmp;
            136        }

            137        _ssubPool[0][i] = 0;
            138
            139        block = _ssubPool[1][i];
            140        while( block )
            141        {
            142            tmp = block->_next;
            143            delete block;
            144            block = tmp;
            145        }

            146        _ssubPool[1][i] = 0;
            147        _ssubPoolSize[i] = 0;
            148    }

            149    forint i = 0; i < _lsubPoolNum; i++ )
            150    {
            151        XMemBlock *block = _lsubPool[0][i], *tmp;
            152        while( block )
            153        {
            154            tmp = block->_next;
            155            delete block;
            156            block = tmp;
            157        }

            158        _lsubPool[0][i] = 0;
            159
            160        block = _lsubPool[1][i];
            161        while( block )
            162        {
            163            tmp = block->_next;
            164            delete block;
            165            block = tmp;
            166        }

            167        _lsubPool[1][i] = 0;
            168        _lsubPoolSize[i] = 0;
            169    }

            170}

            171
            172XMemPool::~XMemPool()
            173{
            174    destroy();
            175    delete []_ssubPoolSize;
            176    delete []_lsubPoolSize;
            177    delete []_ssubPool[0];
            178    delete []_ssubPool[1];
            179    delete []_lsubPool[0];
            180    delete []_lsubPool[1];
            181}

             

            1XMemPool samplePool(4096);
            2XMemBlock *sampleBlock = samplePool.alloc(sizeof(int)*100);
            3int *sampleData = sampleBlock->getMem<int>();
            4samplePool.free(sampleBlock);



            很多細(xì)節(jié)還沒(méi)考慮到,誰(shuí)能為我推薦一個(gè)好的設(shè)計(jì)方案?雙O(1)的

            posted on 2012-03-16 14:32 我執(zhí)分別心 閱讀(1526) 評(píng)論(11)  編輯 收藏 引用

            評(píng)論

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池[未登錄](méi) 2012-03-16 16:54 hdqqq

            在alloc和free中看到了new和delete,這種分配不會(huì)是o(1)的。  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-16 17:00 我執(zhí)分別心

            @hdqqq
            沒(méi)有認(rèn)真看代碼吧, 只是內(nèi)存池滿了OR請(qǐng)求大小超過(guò)上限才會(huì)new delete
            當(dāng)然內(nèi)存池沒(méi)有預(yù)分配,是逐步增長(zhǎng)的  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-16 18:53 陳梓瀚(vczh)

            我以前也做過(guò)類(lèi)似的。首先一個(gè)好的小尺寸緩存池可以O(shè)(1)new和delete這個(gè)顯然你已經(jīng)知道怎么做了,然后準(zhǔn)備8 16 32 64各種尺寸,最后用平衡樹(shù)組織起來(lái)。雖然這嚴(yán)格來(lái)算不是O(1),但是經(jīng)驗(yàn)下他是O(1)的——只要你不要讓節(jié)點(diǎn)有幾十個(gè)那么多。至于大尺寸的,是沒(méi)辦法的。  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-16 19:06 我執(zhí)分別心

            @陳梓瀚(vczh)
            我實(shí)現(xiàn)的這個(gè)雖然有缺陷,但在我的使用范圍內(nèi),確實(shí)是嚴(yán)格O(1)的。如果要用到HASH或樹(shù)之類(lèi)的就是lg(n)的了。 SIZE按冪次增長(zhǎng)我也想過(guò),那樣的話空間浪費(fèi)厲害,不過(guò)跨度比較大的話確實(shí)可以考慮  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-16 19:11 陳梓瀚(vczh)

            @我執(zhí)分別心
            不定尺寸池嚴(yán)格O(1)是不可能的,我不知道我有沒(méi)有理解錯(cuò)你的意思,反正大概就是這個(gè)意思了,如果你要對(duì)付那些頻繁new和delete的場(chǎng)景的話。  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-16 19:24 我執(zhí)分別心

            @陳梓瀚(vczh)
            為什么不可能呢? 我這兒的實(shí)現(xiàn)其實(shí)很簡(jiǎn)單,關(guān)鍵是用block里面的index,它的本質(zhì)是一個(gè)O(1)的HASH, 這樣的代價(jià)就是創(chuàng)建pool的時(shí)候: 非常有必要對(duì)緩存大小事先按需求進(jìn)行合理估計(jì)。  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-16 21:09 yrj

            http://git.savannah.gnu.org/cgit/lwip.git/tree/src/core/memp.c  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-17 03:53 陳梓瀚(vczh)

            @我執(zhí)分別心
            不要以為hash就真的是O(1)的,還記得之前很多語(yǔ)言的hashtable被用來(lái)做DDOS的事情嗎?  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-17 09:25 我執(zhí)分別心

            @陳梓瀚(vczh)
            size_t idx = ( size + _lpoolXep - 1 ) / _lpoolXep - 1; 它是O(1)不?  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池 2012-03-17 09:29 tb

            厲害  回復(fù)  更多評(píng)論   

            # re: 怎么實(shí)現(xiàn)釋放和分配時(shí)間復(fù)雜度都為常數(shù)(O(1))的內(nèi)存池[未登錄](méi) 2012-03-19 08:54 Chipset

            小的容易做到,boundary tags, bitmap, freelist都行,大的需要比較復(fù)雜的數(shù)據(jù)結(jié)構(gòu),建議用PTrie,你可以參考下DLMalloc,谷歌下。

            如果多處理器并行環(huán)境,那就非常困難了,傳統(tǒng)的并發(fā)控制機(jī)制會(huì)成為瓶頸,還要小心False sharing, blowup...,你可以參考下JeMalloc,谷歌下。  回復(fù)  更多評(píng)論   


            只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            導(dǎo)航

            <2012年3月>
            26272829123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統(tǒng)計(jì)

            常用鏈接

            留言簿

            隨筆檔案

            文章分類(lèi)

            最新隨筆

            搜索

            最新評(píng)論

            97久久精品无码一区二区天美| 久久99国产精品一区二区| 99精品久久久久久久婷婷| 久久精品国产亚洲av高清漫画 | 一本久道久久综合狠狠躁AV| 欧美精品一区二区精品久久| 99精品久久精品| 无码人妻久久一区二区三区免费丨 | 精品久久久无码人妻中文字幕| 一本大道加勒比久久综合| 国产精品欧美久久久天天影视| 久久精品国产亚洲av水果派 | 99精品久久精品一区二区| 久久99国产综合精品| 色欲综合久久中文字幕网| 综合网日日天干夜夜久久| 亚洲午夜久久久久妓女影院| 亚洲中文字幕无码一久久区| 日韩乱码人妻无码中文字幕久久| 精产国品久久一二三产区区别 | 久久精品中文字幕久久| 久久99热国产这有精品| 国产L精品国产亚洲区久久| 精品国产婷婷久久久| 亚洲伊人久久成综合人影院| 久久福利资源国产精品999| 中文字幕日本人妻久久久免费 | 欧美精品乱码99久久蜜桃| 久久综合精品国产二区无码| 久久99中文字幕久久| 国内精品久久久久久久亚洲| 日本精品久久久久影院日本| 久久婷婷五月综合色奶水99啪| 久久精品国产亚洲av高清漫画| 久久亚洲欧美日本精品| 无码任你躁久久久久久| 亚洲欧美日韩中文久久| 久久婷婷综合中文字幕| 久久精品国产亚洲Aⅴ香蕉| 久久久亚洲欧洲日产国码是AV | 国产亚洲色婷婷久久99精品91|