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

那誰的技術博客

感興趣領域:高性能服務器編程,存儲,算法,Linux內核
隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
數據加載中……

服務器公共庫開發-內存池管理模塊

這個內存池之前已經介紹過了,在這里

這次整理自己的服務器公共庫,沒有忘記這個好東西,算法沒有改變,但是有兩個變化:
1) 我認為這個模塊對于一個服務器而言, 應該是一個單件, 所以它繼承自前面說過的singleton基類.
2) 加入了線程鎖, 同樣是可以配置的, 因為我基本不寫多線程的服務器, 不過, 還是把接口保留在那里吧, 如果需要可以打開以支持多線程.

mempool.h:
/********************************************************************
    created:    2008/08/03
    filename:   mempool.h    
    author:        Lichuang
                
    purpose:    仿SGI STL內存池的實現
********************************************************************
*/

#ifndef __MEM_POOL_H__
#define __MEM_POOL_H__

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

// 字節對齊數
#define ALIGN                512
// 最大BLOCK的尺寸
#define MAX_BLOCK_SIZE        20 * 1024
// HASH表的數量
#define BLOCK_LIST_NUM        (MAX_BLOCK_SIZE) / (ALIGN)
// HASH表中每次初始化時LIST中元素的數量
#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內存池的實現, 可以配置是否支持多線程
********************************************************************
*/

#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的內存
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)
    {
        
// 如果之前沒有分配, 或者已經分配完畢了, 就調用refill函數重新分配
        
// 需要注意的是, 傳入refill的參數是經過對齊處理的
        pResult = (Obj*)Refill(RoundUp(nSize));
    }
    
else
    {
        
// 否則就更新該HASH表的LIST頭節點指向下一個LIST的節點, 當分配完畢時, 頭結點為NULL
        *ppFreeList = pResult->pFreeListLink;
    }

    THREAD_UNLOCK;

    
return pResult;
}

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

    
// 如果超過內存池所能承受的最大尺寸, 調用系統API重新分配內存
    if (nOldSize > (size_t)MAX_BLOCK_SIZE && nNewSize > (size_t)MAX_BLOCK_SIZE)
    {
        
return ::realloc(p, nNewSize);
    }

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

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

    
return pResult;
}

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

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

    
// 將回收的內存作為鏈表的頭回收
    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;
    
// 總共所需的內存
    size_t nTotalBytes = nSize * nObjs;
    
// 剩余的內存
    size_t nBytesLeft = m_pEndFree - m_pStartFree;

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

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

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

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

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

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

    
// 從下一個HASH-LIST中尋找可用的內存
    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是經過字節對齊處理的數
void* CMemPool::Refill(size_t n)
{
    
// 每個鏈表每次初始化時最多LIST_NODE_NUM個元素
    int nObjs = LIST_NODE_NUM;
    
char* pChunk = AllocChunk(n, nObjs);
    Obj
** ppFreeList;
    Obj
* pResult;
    Obj 
*pCurrentObj, *pNextObj;
    
int i;

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

    
// 獲得請求的內存地址
    pResult = (Obj*)pChunk;
    
// 請求了一個單位內存, 減少一個計數
    --nObjs;
    
// 從下一個單位開始將剩余的obj連接起來
    *ppFreeList = pNextObj = (Obj*)(pChunk + n);

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

        
// 分配完畢, 下一個節點為NULL, 退出循環
        if (nObjs == i)
        {
            pCurrentObj
->pFreeListLink = NULL;
            
break;
        }

        pCurrentObj
->pFreeListLink = pNextObj;
    }

    
return pResult;
}



posted on 2008-08-11 23:30 那誰 閱讀(4712) 評論(14)  編輯 收藏 引用 所屬分類: 算法與數據結構服務器設計Linux/Unix

評論

# re: 服務器公共庫開發-內存池管理模塊  回復  更多評論   

內存池作為單件會嚴重減小適應范圍的
2008-08-12 01:04 | 陳梓瀚(vczh)

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

覺得boost::pool是個不錯的東西,沒什么必要自已重新造一個沒別人好的車輪
2008-08-12 09:08 | ricardo

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

@ricardo
我不用boost,也不會用,謝謝.
2008-08-12 09:54 |

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

最好不要用單件。

可以使用簡化的slab來做內存池/對象池——雖然不支持可變長度對象,但其使用范圍更廣也更靈活。
2008-08-12 10:24 | raof01

# re: 服務器公共庫開發-內存池管理模塊  回復  更多評論   

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

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

樓上的朋友別激動,之所以選擇自己寫這個庫,是因為我是閱讀過它相關的代碼明白其原理的,而且想動手實踐一下,以在真正的應用中體會其性能等,諸如boost之類的第三方庫,第一我不了解, 第二我不想在封裝的庫中引入別的庫,所以除非必要否則我是不想使用的.

至于為什么這里封裝成單件,我說了,這是一個服務器的公共庫,而我認為,在一個運行的服務器上,這樣的模塊應該只有一個, 所有請求分配內存的操作都去找這個模塊申請內存.

2008-08-12 10:59 |

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

另外,我認為這個模塊也是一個"第三方庫", 因為它是從SGI實現的STL代碼中提取出來的,并不是完全的"造輪子".
2008-08-12 11:05 |

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

覺得模塊劃分粒度不夠細。可以分成兩個類,這樣復用程度高一點:
1、m_szFreeList的每個表項可以封裝成一個類。策略很多,找一個合適的就行。比如:
|head

-------------------------------------
|size|    |////|size|    |////|size|
|----|free|////|----|free|////|----|free
|next|    |////|next|    |////|next|
-------------------------------------
   |           ︿ |            ︿ |
   |           | |            | v
    -----------   ------------  NULL
當然,復雜性會有很大的增加,比如合并內存碎片。
2、用你的hash表來組織第一個類的對象。
2008-08-12 11:58 | raof01

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

內存池原理很簡單,
boost的內存池做的還可以,至少是夠用的,
另外Apache下的ARP(貌似叫這個名字)中的內存池實現的也很不錯。

其實STL中的Vector就可以當作一個池來用,在實際應用中能夠適用我遇到的很多情況。

自己寫寫挺好的,雖然原理簡單,但是還是需要比較扎實的基礎知識才能做好的。做出來容易,做好難啊。
2008-08-12 12:28 | 楊粼波

# re: 服務器公共庫開發-內存池管理模塊[未登錄]  回復  更多評論   

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

# re: 服務器公共庫開發-內存池管理模塊  回復  更多評論   

@創
確實,這個也算不做造輪子。之前我基本上將SGI的內存池翻譯成C代碼,所以我對那一塊比較熟悉。一看你的代碼,我就覺得很眼熟。:D

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

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

# re: 服務器公共庫開發-內存池管理模塊  回復  更多評論   

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

@ricardo
個人以為boost pool不怎么好,還是請橫向對比一下其他的內存池設計。

國人許式偉有一個AllocFree不錯,不過是單線程的。

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

# re: 服務器公共庫開發-內存池管理模塊  回復  更多評論   

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

# re: 服務器公共庫開發-內存池管理模塊  回復  更多評論   

http://www.codeproject.com/KB/cpp/pools.aspx
很精巧,不過是分配定長的
2008-12-05 19:32 | minus
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产热re99久久6国产精品| 一区二区三区高清不卡| 夜夜夜久久久| 1000部精品久久久久久久久| 国产麻豆精品在线观看| 国产精品av免费在线观看| 欧美日韩亚洲91| 欧美视频在线观看免费网址| 欧美日本国产| 国产美女精品一区二区三区| 国产午夜亚洲精品不卡| 国产一区二区三区在线观看视频| 国产综合在线视频| 91久久国产综合久久蜜月精品| 亚洲人成网站影音先锋播放| 中国成人黄色视屏| 久久国产加勒比精品无码| 老司机亚洲精品| 最近中文字幕mv在线一区二区三区四区| 亚洲国产高潮在线观看| 日韩一级大片在线| 性欧美大战久久久久久久免费观看| 久久精精品视频| 欧美日韩1区2区| 激情欧美国产欧美| 亚洲青色在线| 欧美一区二区大片| 亚洲激情国产精品| 欧美一级在线视频| 欧美日韩一区二区三区高清| 国产主播一区| 亚洲无限av看| 亚洲丰满少妇videoshd| 亚洲摸下面视频| 欧美激情亚洲视频| 亚洲高清三级视频| 亚洲欧美日韩在线综合| 欧美国产极速在线| 欧美自拍偷拍| 国产精品成人播放| 99re国产精品| 欧美高清在线播放| 久久精品国产清自在天天线 | 久久精品一区四区| 国产精品99一区| 亚洲精品一级| 欧美成年视频| 午夜亚洲性色视频| 欧美日韩精品在线观看| 91久久黄色| 欧美成人dvd在线视频| 亚洲欧美日韩国产另类专区| 欧美伦理a级免费电影| 中文精品在线| 欧美国产日韩a欧美在线观看| 一区二区三区在线看| 久久国内精品自在自线400部| 一本一本a久久| 欧美精品福利视频| 亚洲欧洲日夜超级视频| 欧美国产精品中文字幕| 免费成人性网站| 亚洲国产成人不卡| 麻豆精品视频在线| 久久理论片午夜琪琪电影网| 黄色日韩精品| 久久精品国产综合| 欧美专区在线播放| 国内精品久久久久久久影视麻豆| 久久精品国产亚洲一区二区三区| 亚洲综合首页| 狠狠入ady亚洲精品经典电影| 欧美一区二区三区精品| 亚洲午夜精品一区二区| 国产女主播一区二区三区| 久久久xxx| 免费观看成人网| 亚洲精品欧美精品| 99精品久久久| 国产欧美日韩免费| 免费观看成人鲁鲁鲁鲁鲁视频| 免费观看30秒视频久久| 一本色道久久综合亚洲二区三区 | 免费永久网站黄欧美| 亚洲国产导航| 日韩一级精品| 国产欧美日韩视频在线观看| 久久久久国内| 欧美电影免费观看大全| 亚洲一区二区三区乱码aⅴ蜜桃女| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 在线欧美一区| 亚洲精品国产精品国自产观看浪潮 | 久久综合久久久| 亚洲另类在线一区| 亚洲综合另类| 在线看片日韩| 99国产精品国产精品久久| 国产欧美一区二区三区沐欲 | 亚洲午夜激情网站| 永久免费视频成人| 亚洲美女精品一区| 最新日韩中文字幕| 性做久久久久久免费观看欧美| 欧美一区二区三区在线| 日韩亚洲综合在线| 午夜精品亚洲| 一本色道久久综合亚洲精品婷婷| 亚洲女性喷水在线观看一区| 亚洲国产综合视频在线观看| 一区二区三区欧美在线| 亚洲国产日韩在线| 午夜精品久久久久| 亚洲影院在线| 免播放器亚洲一区| 久久久一本精品99久久精品66| 国产精品福利网| 亚洲精品日韩在线| 亚洲福利视频免费观看| 亚洲男人的天堂在线观看| 日韩一区二区免费高清| 久久久久99精品国产片| 欧美亚洲免费电影| 国产精品美女主播| 一本一本a久久| 中文亚洲欧美| 欧美日韩不卡合集视频| 蜜桃av噜噜一区| 国产亚洲福利一区| 亚洲免费一级电影| 亚洲欧美一区二区三区极速播放 | 午夜精品影院| 欧美日韩伦理在线免费| 亚洲国产精品电影| 最新国产拍偷乱拍精品| 久久久久欧美精品| 久久久久**毛片大全| 国产视频自拍一区| 欧美在线综合视频| 久久久久久久久久码影片| 国产亚洲精品久久久| 亚洲欧美日韩国产中文| 午夜精品久久久久久久99黑人| 欧美精品自拍偷拍动漫精品| 亚洲国产日韩在线| 亚洲免费观看| 欧美日韩中文字幕综合视频| 亚洲日本欧美天堂| 亚洲在线一区二区三区| 国产精品人人做人人爽人人添| 在线视频欧美一区| 午夜一级久久| 国语自产精品视频在线看一大j8| 欧美一区二区女人| 免费亚洲电影在线观看| 亚洲日本电影在线| 欧美午夜精品久久久久久人妖| 亚洲一区三区视频在线观看| 久久av红桃一区二区小说| 黑丝一区二区三区| 欧美另类99xxxxx| 在线亚洲欧美视频| 久久久久国产精品午夜一区| 禁久久精品乱码| 欧美成人精品在线播放| aa级大片欧美三级| 久久久99爱| 一二三区精品福利视频| 国产精品热久久久久夜色精品三区| 一本久久综合| 亚洲国产另类久久精品| 欧美绝品在线观看成人午夜影视| 亚洲调教视频在线观看| 老司机成人网| 亚洲伊人一本大道中文字幕| 国产亚洲激情在线| 欧美日韩精品免费观看视一区二区 | 亚洲午夜影视影院在线观看| 国产欧美一区二区精品性| 蜜桃av噜噜一区| 午夜精品www| 亚洲精选成人| 免费在线国产精品| 亚洲午夜精品在线| 在线精品亚洲| 国产区二精品视| 欧美精品福利在线| 久久天天躁夜夜躁狠狠躁2022| 99这里只有久久精品视频| 久久久久久久国产| 午夜精品在线看| 日韩一级在线观看| 激情久久五月| 国产视频不卡| 国产精品成人v| 老牛嫩草一区二区三区日本| 欧美伊人影院| 午夜亚洲福利| 亚洲欧美欧美一区二区三区| 亚洲美女av在线播放|