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

            那誰(shuí)的技術(shù)博客

            感興趣領(lǐng)域:高性能服務(wù)器編程,存儲(chǔ),算法,Linux內(nèi)核
            隨筆 - 210, 文章 - 0, 評(píng)論 - 1183, 引用 - 0
            數(shù)據(jù)加載中……

            服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊

            這個(gè)內(nèi)存池之前已經(jīng)介紹過(guò)了,在這里

            這次整理自己的服務(wù)器公共庫(kù),沒(méi)有忘記這個(gè)好東西,算法沒(méi)有改變,但是有兩個(gè)變化:
            1) 我認(rèn)為這個(gè)模塊對(duì)于一個(gè)服務(wù)器而言, 應(yīng)該是一個(gè)單件, 所以它繼承自前面說(shuō)過(guò)的singleton基類.
            2) 加入了線程鎖, 同樣是可以配置的, 因?yàn)槲一静粚?xiě)多線程的服務(wù)器, 不過(guò), 還是把接口保留在那里吧, 如果需要可以打開(kāi)以支持多線程.

            mempool.h:
            /********************************************************************
                created:    2008/08/03
                filename:   mempool.h    
                author:        Lichuang
                            
                purpose:    仿SGI STL內(nèi)存池的實(shí)現(xiàn)
            ********************************************************************
            */

            #ifndef __MEM_POOL_H__
            #define __MEM_POOL_H__

            #include 
            "singleton.h"
            #include 
            "threadmutex.h"
            #include 
            <stdio.h>

            // 字節(jié)對(duì)齊數(shù)
            #define ALIGN                512
            // 最大BLOCK的尺寸
            #define MAX_BLOCK_SIZE        20 * 1024
            // HASH表的數(shù)量
            #define BLOCK_LIST_NUM        (MAX_BLOCK_SIZE) / (ALIGN)
            // HASH表中每次初始化時(shí)LIST中元素的數(shù)量
            #define LIST_NODE_NUM        20

            class CMemPool
                : CSingleton
            <CMemPool>
            {
            public:
                
            void* Allocate(size_t nSize);
                
            void* Reallocate(void* p, size_t nOldSize, size_t nNewSize);
                
            void  Deallocate(void* p, size_t nSize);
                
            int   GetMemSize();

            private:
                CMemPool();
                
            virtual ~CMemPool();

                
            char* AllocChunk(size_t nSize, int& nObjs);
                
            void* Refill(size_t n);
                size_t RoundUp(size_t nBytes);
                
            int GetFreeListIndex(size_t nBytes);

            private:
                DECLARE_SINGLETON_CLASS(CMemPool)

            private:        
                union Obj
                {
                    union Obj
            * pFreeListLink;
                    
            char szData[1];
                };

                Obj
            * m_szFreeList[BLOCK_LIST_NUM];

                
            char* m_pStartFree;
                
            char* m_pEndFree;
                size_t m_nHeapSize;
                CThreadMutex m_tThreadMutex;
            };

            #endif /* __MEM_POOL_H__ */


            mempool.cpp:
            /********************************************************************
                created:    2008/08/01
                filename:     mempool.h
                author:        Lichuang
                            
                purpose:    模擬SGI STL內(nèi)存池的實(shí)現(xiàn), 可以配置是否支持多線程
            ********************************************************************
            */

            #include 
            "mempool.h"
            #include 
            <string.h>

            CMemPool::CMemPool()
                : m_pStartFree(NULL)
                , m_pEndFree(NULL)
                , m_nHeapSize(
            0)                      
            {
                ::memset(m_szFreeList, 
            0sizeof(m_szFreeList));
            }

            CMemPool::
            ~CMemPool()
            {
            }

            // 從內(nèi)存池中分配尺寸為n的內(nèi)存
            void* CMemPool::Allocate(size_t nSize)
            {
                
            if (nSize > MAX_BLOCK_SIZE)
                {
                    
            return ::malloc(nSize);
                }
                
            if (0 >= nSize)
                {
                    
            return NULL;
                }

                Obj
            ** ppFreeList;
                Obj
            *  pResult;

                THREAD_LOCK;

                
            // 獲得尺寸n的HASH表地址
                ppFreeList = m_szFreeList + GetFreeListIndex(nSize);
                pResult 
            = *ppFreeList;
                
            if (NULL == pResult)
                {
                    
            // 如果之前沒(méi)有分配, 或者已經(jīng)分配完畢了, 就調(diào)用refill函數(shù)重新分配
                    
            // 需要注意的是, 傳入refill的參數(shù)是經(jīng)過(guò)對(duì)齊處理的
                    pResult = (Obj*)Refill(RoundUp(nSize));
                }
                
            else
                {
                    
            // 否則就更新該HASH表的LIST頭節(jié)點(diǎn)指向下一個(gè)LIST的節(jié)點(diǎn), 當(dāng)分配完畢時(shí), 頭結(jié)點(diǎn)為NULL
                    *ppFreeList = pResult->pFreeListLink;
                }

                THREAD_UNLOCK;

                
            return pResult;
            }

            void* CMemPool::Reallocate(void* p, size_t nOldSize, size_t nNewSize)
            {
                
            void* pResult;
                size_t nCopySize;

                
            // 如果超過(guò)內(nèi)存池所能承受的最大尺寸, 調(diào)用系統(tǒng)API重新分配內(nèi)存
                if (nOldSize > (size_t)MAX_BLOCK_SIZE && nNewSize > (size_t)MAX_BLOCK_SIZE)
                {
                    
            return ::realloc(p, nNewSize);
                }

                
            // 如果新老內(nèi)存尺寸在對(duì)齊之后相同, 那么直接返回
                if (RoundUp(nOldSize) == RoundUp(nNewSize))
                    
            return p;

                
            // 首先按照新的尺寸分配內(nèi)存
                pResult = Allocate(nNewSize);
                
            if (NULL == pResult)
                {
                    
            return NULL;
                }
                
            // copy舊內(nèi)存的數(shù)據(jù)到新的內(nèi)存區(qū)域
                nCopySize = nNewSize > nOldSize ? nOldSize : nNewSize;
                ::memcpy(pResult, p, nCopySize);
                
            // 釋放舊內(nèi)存區(qū)域
                Deallocate(p, nOldSize);

                
            return pResult;
            }

            // 將尺寸為n的內(nèi)存回收到內(nèi)存池中
            void CMemPool::Deallocate(void* p, size_t nSize)
            {
                Obj
            * pObj = (Obj *)p;
                Obj 
            **ppFreeList;

                
            if (0 >= nSize)
                {
                    
            return;
                }
                
            // 如果要回收的內(nèi)存大于MAX_BLOCK_SIZE, 直接調(diào)用free回收內(nèi)存
                if (nSize > MAX_BLOCK_SIZE)
                {
                    ::free(p);
                    
            return;
                }

                
            // 將回收的內(nèi)存作為鏈表的頭回收
                ppFreeList = m_szFreeList + GetFreeListIndex(nSize);

                THREAD_LOCK;

                pObj
            ->pFreeListLink = *ppFreeList;
                
            *ppFreeList = pObj;

                THREAD_UNLOCK;
            }

            int CMemPool::GetMemSize()
            {
                
            return m_nHeapSize;
            }

            size_t CMemPool::RoundUp(size_t nBytes)
            {
                
            return (nBytes + ALIGN - 1& ~(ALIGN - 1);
            }

            int CMemPool::GetFreeListIndex(size_t nBytes)
            {
                
            return (nBytes + ALIGN - 1/ ALIGN - 1;
            }


            char* CMemPool::AllocChunk(size_t nSize, int& nObjs)
            {
                
            char* pResult;
                
            // 總共所需的內(nèi)存
                size_t nTotalBytes = nSize * nObjs;
                
            // 剩余的內(nèi)存
                size_t nBytesLeft = m_pEndFree - m_pStartFree;

                
            // 如果剩余的內(nèi)存可以滿足需求, 就直接返回之, 并且更新內(nèi)存池的指針
                if (nBytesLeft >= nTotalBytes)
                {
                    pResult 
            = m_pStartFree;
                    m_pStartFree 
            += nTotalBytes;
                    
            return pResult;
                }

                
            // 如果剩余的內(nèi)存大于單位內(nèi)存數(shù)量, 也就是說(shuō)至少還可以分配一個(gè)單位內(nèi)存
                
            // 計(jì)算出最多可以分配多少塊單位內(nèi)存, 保存至nobjs, 返回內(nèi)存的指針
                if (nBytesLeft >= nSize)
                {
                    nObjs 
            = (int)(nBytesLeft / nSize);
                    nTotalBytes 
            = nSize * nObjs;
                    pResult 
            = m_pStartFree;
                    m_pStartFree 
            += nTotalBytes;
                    
            return pResult;
                }

                
            // 如果還有剩余的內(nèi)存, 將它放到對(duì)應(yīng)的HASH-LIST頭部
                if (0 < nBytesLeft)
                {
                    Obj
            ** ppFreeList = m_szFreeList + GetFreeListIndex(nBytesLeft);
                    ((Obj
            *)m_pStartFree)->pFreeListLink = *ppFreeList;
                    
            *ppFreeList = (Obj*)m_pStartFree;
                }

                
            // 需要獲取的內(nèi)存, 注意第一次分配都要兩倍于total_bytes的大小
                
            // 同時(shí)要加上原有的heap_size / 4的對(duì)齊值
                size_t nBytesToGet = 2 * nTotalBytes + RoundUp(m_nHeapSize >> 4);
                m_pStartFree 
            = (char*)::malloc(nBytesToGet);

                
            // 獲取成功 重新調(diào)用chunk_alloc函數(shù)分配內(nèi)存
                if (NULL != m_pStartFree)
                {
                    m_nHeapSize 
            += nBytesToGet;
                    m_pEndFree 
            = m_pStartFree + nBytesToGet;
                    
            return AllocChunk(nSize, nObjs);
                }

                
            // 下面是獲取不成功的處理.

                
            // 從下一個(gè)HASH-LIST中尋找可用的內(nèi)存
                int i = (int)GetFreeListIndex(nSize) + 1;
                Obj 
            **ppFreeList, *p;
                
            for (; i < BLOCK_LIST_NUM; ++i)
                {
                    ppFreeList 
            = m_szFreeList + i;
                    p 
            = *ppFreeList;

                    
            if (NULL != p)
                    {
                        
            *ppFreeList = p->pFreeListLink;
                        m_pStartFree 
            = (char*)p;
                        m_pEndFree 
            = m_pStartFree + (i + 1* ALIGN;
                        
            return AllocChunk(nSize, nObjs);
                    }
                }

                m_pEndFree 
            = NULL;

                
            return NULL;
            }

            // 重新分配尺寸為n的內(nèi)存, 其中n是經(jīng)過(guò)字節(jié)對(duì)齊處理的數(shù)
            void* CMemPool::Refill(size_t n)
            {
                
            // 每個(gè)鏈表每次初始化時(shí)最多LIST_NODE_NUM個(gè)元素
                int nObjs = LIST_NODE_NUM;
                
            char* pChunk = AllocChunk(n, nObjs);
                Obj
            ** ppFreeList;
                Obj
            * pResult;
                Obj 
            *pCurrentObj, *pNextObj;
                
            int i;

                
            // 如果只請(qǐng)求成功了一個(gè)元素, 直接返回之
                if (1 == nObjs)
                {
                    
            return pChunk;
                }
                
            // 獲得尺寸n的HASH表地址
                ppFreeList = m_szFreeList + GetFreeListIndex(n);

                
            // 獲得請(qǐng)求的內(nèi)存地址
                pResult = (Obj*)pChunk;
                
            // 請(qǐng)求了一個(gè)單位內(nèi)存, 減少一個(gè)計(jì)數(shù)
                --nObjs;
                
            // 從下一個(gè)單位開(kāi)始將剩余的obj連接起來(lái)
                *ppFreeList = pNextObj = (Obj*)(pChunk + n);

                
            // 將剩余的obj連接起來(lái)
                for (i = 1; ; ++i)
                {
                    pCurrentObj 
            = pNextObj;
                    pNextObj 
            = (Obj*)((char*)pNextObj + n);

                    
            // 分配完畢, 下一個(gè)節(jié)點(diǎn)為NULL, 退出循環(huán)
                    if (nObjs == i)
                    {
                        pCurrentObj
            ->pFreeListLink = NULL;
                        
            break;
                    }

                    pCurrentObj
            ->pFreeListLink = pNextObj;
                }

                
            return pResult;
            }



            posted on 2008-08-11 23:30 那誰(shuí) 閱讀(4687) 評(píng)論(14)  編輯 收藏 引用 所屬分類: 算法與數(shù)據(jù)結(jié)構(gòu)服務(wù)器設(shè)計(jì)Linux/Unix

            評(píng)論

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊  回復(fù)  更多評(píng)論   

            內(nèi)存池作為單件會(huì)嚴(yán)重減小適應(yīng)范圍的
            2008-08-12 01:04 | 陳梓瀚(vczh)

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            覺(jué)得boost::pool是個(gè)不錯(cuò)的東西,沒(méi)什么必要自已重新造一個(gè)沒(méi)別人好的車輪
            2008-08-12 09:08 | ricardo

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            @ricardo
            我不用boost,也不會(huì)用,謝謝.
            2008-08-12 09:54 | 創(chuàng)

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            最好不要用單件。

            可以使用簡(jiǎn)化的slab來(lái)做內(nèi)存池/對(duì)象池——雖然不支持可變長(zhǎng)度對(duì)象,但其使用范圍更廣也更靈活。
            2008-08-12 10:24 | raof01

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊  回復(fù)  更多評(píng)論   

            “沒(méi)什么必要自已重新造一個(gè)沒(méi)別人好的車輪”就是因?yàn)槲覀儑?guó)家太多的程序員有這樣的潛意識(shí),導(dǎo)致我們知其然而不知其所以然。自己造車輪是好事,強(qiáng)烈支持造車輪者。
            毛主席當(dāng)年如果沒(méi)有讓我國(guó)航天人員自己造車輪,他們現(xiàn)在恐怕又得跟在老美、老英屁股后面拾糞了。開(kāi)玩笑的說(shuō)法就是:吃屎都趕不上熱的。和航天事業(yè)形成鮮明對(duì)比的就是航空,我們的大飛機(jī)項(xiàng)目今年才啟動(dòng),開(kāi)始嘗試自己造車輪,強(qiáng)烈感謝胡主席和溫總理,感謝他們的獨(dú)具慧眼,感謝他們給當(dāng)代航空有志青年帶來(lái)希望,帶來(lái)工作機(jī)會(huì),雖然慢了幾拍。但是我相信再遠(yuǎn)的目標(biāo),只要開(kāi)始就能實(shí)現(xiàn)!中國(guó)加油!
            有能力造車的人,能夠更好的使用別人的車,進(jìn)而改進(jìn)自己的造車技術(shù),這是一個(gè)良構(gòu)的循環(huán),是一個(gè)具有創(chuàng)新能力和自優(yōu)化能力的循環(huán);而一味的買(mǎi)別人的車使用,成本大是小事,萬(wàn)一他娘的鬼子們不賣(mài)給咱新車、好車呢,咱們只能干瞪眼了!
            -------------------- 以上僅代表個(gè)人觀點(diǎn)、與C++博客無(wú)關(guān)。
            2008-08-12 10:46 | 金哥

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            樓上的朋友別激動(dòng),之所以選擇自己寫(xiě)這個(gè)庫(kù),是因?yàn)槲沂情喿x過(guò)它相關(guān)的代碼明白其原理的,而且想動(dòng)手實(shí)踐一下,以在真正的應(yīng)用中體會(huì)其性能等,諸如boost之類的第三方庫(kù),第一我不了解, 第二我不想在封裝的庫(kù)中引入別的庫(kù),所以除非必要否則我是不想使用的.

            至于為什么這里封裝成單件,我說(shuō)了,這是一個(gè)服務(wù)器的公共庫(kù),而我認(rèn)為,在一個(gè)運(yùn)行的服務(wù)器上,這樣的模塊應(yīng)該只有一個(gè), 所有請(qǐng)求分配內(nèi)存的操作都去找這個(gè)模塊申請(qǐng)內(nèi)存.

            2008-08-12 10:59 | 創(chuàng)

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            另外,我認(rèn)為這個(gè)模塊也是一個(gè)"第三方庫(kù)", 因?yàn)樗菑腟GI實(shí)現(xiàn)的STL代碼中提取出來(lái)的,并不是完全的"造輪子".
            2008-08-12 11:05 | 創(chuàng)

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            覺(jué)得模塊劃分粒度不夠細(xì)。可以分成兩個(gè)類,這樣復(fù)用程度高一點(diǎn):
            1、m_szFreeList的每個(gè)表項(xiàng)可以封裝成一個(gè)類。策略很多,找一個(gè)合適的就行。比如:
            |head

            -------------------------------------
            |size|    |////|size|    |////|size|
            |----|free|////|----|free|////|----|free
            |next|    |////|next|    |////|next|
            -------------------------------------
               |           ︿ |            ︿ |
               |           | |            | v
                -----------   ------------  NULL
            當(dāng)然,復(fù)雜性會(huì)有很大的增加,比如合并內(nèi)存碎片。
            2、用你的hash表來(lái)組織第一個(gè)類的對(duì)象。
            2008-08-12 11:58 | raof01

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            內(nèi)存池原理很簡(jiǎn)單,
            boost的內(nèi)存池做的還可以,至少是夠用的,
            另外Apache下的ARP(貌似叫這個(gè)名字)中的內(nèi)存池實(shí)現(xiàn)的也很不錯(cuò)。

            其實(shí)STL中的Vector就可以當(dāng)作一個(gè)池來(lái)用,在實(shí)際應(yīng)用中能夠適用我遇到的很多情況。

            自己寫(xiě)寫(xiě)挺好的,雖然原理簡(jiǎn)單,但是還是需要比較扎實(shí)的基礎(chǔ)知識(shí)才能做好的。做出來(lái)容易,做好難啊。
            2008-08-12 12:28 | 楊粼波

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊[未登錄](méi)  回復(fù)  更多評(píng)論   

            @楊粼波
            同意。博主牛。
            2008-08-12 12:45 | raof01

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊  回復(fù)  更多評(píng)論   

            @創(chuàng)
            確實(shí),這個(gè)也算不做造輪子。之前我基本上將SGI的內(nèi)存池翻譯成C代碼,所以我對(duì)那一塊比較熟悉。一看你的代碼,我就覺(jué)得很眼熟。:D

            @金哥
            同意你的說(shuō)法。我覺(jué)得我們周圍有很多程序員都抱著這樣的想法。他們總以“不重造輪子”的觀點(diǎn)告誡自己,從而不知道很多東西的底層實(shí)現(xiàn)原理。就像有些程序員以“盲目的優(yōu)化只會(huì)適得其反”這樣觀點(diǎn)為理由,而忽視了優(yōu)化的重要性一樣。

            不重造輪子,是基于你懂得造輪子的原理基礎(chǔ)上的。而如果你自己都不懂,連重造輪子的能力都沒(méi)有,那基本就比重造輪子的人還差了。
            2008-08-13 10:13 | Kevin Lynx

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊  回復(fù)  更多評(píng)論   

            @楊粼波
            是apr_pool,是目前最好的內(nèi)存池之一(其實(shí)我認(rèn)為“之一”可以去掉),是C實(shí)現(xiàn)。
            不過(guò)C++方面我個(gè)人更傾向于采用loki的smallobj的算法。loki的編程風(fēng)格不太習(xí)慣,所以通常也是自己實(shí)現(xiàn)一次(好吧,是抄襲,哦呵呵)。

            @ricardo
            個(gè)人以為boost pool不怎么好,還是請(qǐng)橫向?qū)Ρ纫幌缕渌膬?nèi)存池設(shè)計(jì)。

            國(guó)人許式偉有一個(gè)AllocFree不錯(cuò),不過(guò)是單線程的。

            btw,嚴(yán)重同意金哥,kevinlynx的看法。如果不是很趕時(shí)間,越是基礎(chǔ)的東西,越是自己寫(xiě)一次的好。
            2008-08-14 13:06 | 矩陣操作

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊  回復(fù)  更多評(píng)論   

            內(nèi)存池要保證一般情況下,在O(1)時(shí)間內(nèi)分配到請(qǐng)求的內(nèi)存。你這個(gè)似乎不可以。
            2008-08-15 12:55 | x-matrix

            # re: 服務(wù)器公共庫(kù)開(kāi)發(fā)-內(nèi)存池管理模塊  回復(fù)  更多評(píng)論   

            http://www.codeproject.com/KB/cpp/pools.aspx
            很精巧,不過(guò)是分配定長(zhǎng)的
            2008-12-05 19:32 | minus
            麻豆成人久久精品二区三区免费 | 99久久久精品免费观看国产| 精品久久久久久中文字幕大豆网| 亚洲日韩中文无码久久| 久久成人国产精品| 国产AV影片久久久久久| 午夜精品久久久久久影视777| 日韩亚洲国产综合久久久| 久久人人爽人人人人爽AV| 精品乱码久久久久久久| 精品国产91久久久久久久a| 日产精品久久久久久久| 久久免费视频网站| 亚洲精品国产第一综合99久久| 久久精品中文騷妇女内射| 久久av高潮av无码av喷吹| 久久精品青青草原伊人| 青青青青久久精品国产| 一日本道伊人久久综合影| 国产精品福利一区二区久久| 性欧美大战久久久久久久| 2021久久精品国产99国产精品| 人妻少妇精品久久| 久久久久AV综合网成人| 精品久久久久久无码不卡| 久久综合久久综合久久| 国内精品人妻无码久久久影院导航| 欧美激情精品久久久久| 久久综合九色综合网站| 精品国产热久久久福利| 成人妇女免费播放久久久| 久久久久青草线蕉综合超碰| 国产AV影片久久久久久| 久久久久成人精品无码中文字幕| 亚洲欧美一级久久精品| 香蕉久久一区二区不卡无毒影院| 一本色道久久88—综合亚洲精品| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区 | 精品久久久久久久久久中文字幕| 久久久久国产精品熟女影院| 久久久久久曰本AV免费免费|