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

posts - 15,comments - 21,trackbacks - 0
      寫服務器的,通常會涉及到內存池的東西,自己在這方面也看了寫了一些東西,有些體會,寫出來跟大家分享下。
      內存池基本包含以下幾個東西,第一,初始化。第二,分配內存。第三,回收內存。所謂初始化,就是在服務器啟動的時候,或者第一次需要內存的時候,系統分配很大的一塊內存,方便之后的使用。分配內存,就是從內存池中取出需要的內存給外部使用,當然這里需要考慮的是當內存池中沒有內存可分配時候的處理。回收內存,簡單來說,就是外面對象生命期結束了,將分配出去的內存回收入內存池中。好了簡單概念就說完了,我們先來看一種最簡單的設計方式。
//為了方便描述,這里附上幾個簡單的鏈表操作宏
#define INSERT_TO_LIST( head, item, prev, next ) \
do{ \
if ( head ) \
(head)->prev = (item); \
(item)->next = (head); \
(head) = (item);          \
}while(0)
#define REMOVE_FROM_LIST(head, item, prev, next) \
do{ \
if ( (head) == (item) ) \
{ \
(head) = (item)->next; \
if ( head ) \
(head)->prev = NULL; \
} \
else \
{ \
if ( (item)->prev ) \
(item)->prev->next = (item)->next;          \
\
if ( (item)->next ) \
(item)->next->prev = (item)->prev;          \
} \
}while(0)
struct student
{
      char name[32];
      byte sex;
      
      struct student *prev,*next;
};

static struct mem_pool
{
      //該指針用來記錄空閑節點
      
struct student *free;
      //該變量記錄分配結點個數
      size_t alloc_cnt;
}s_mem_pool;

//分配內存“塊”的函數
bool mem_pool_resize(size_t size)
{
      //該函數創建size個不連續的對象,把他們通過鏈表的方式加入到s_mem_pool.free中
      for ( size_t i = 0;i < size;++i )
      {
            
struct student *p = (struct student *)malloc(sizeof(struct student));
            
if ( !p )
               return false;
            
            p->prev = p->next = NULL;
            INSERT_TO_LIST(s_mem_pool.free,p,prev,next);

      }

      s_mem_pool.alloc_cnt += size;
}

#define MEM_INIT_SIZE 512  
#define MEM_INC_SIZE 256
//初始化函數
bool mem_pool_init()
{
if ( !mem_pool_resize(MEM_INIT_SIZE) )
            return false;
return true;
}
struct student *get_data()
{
if ( s_mem_pool.free == NULL )
{
            if ( !mem_pool_resize(MEM_INC_SIZE) )
                  return NULL;
}
struct student *ret = s_mem_pool.free;
REMOVE_FROM_LIST(s_mem_pool.free,ret,prev,next)
return ret;
}
void free_data(struct student *p)
{
if ( !p )
            return;
memset(p,0,sizeof(struct student));
INSERT_TO_LIST(s_mem_pool.free,p,prev,next)
}
好了最簡單的內存池的大致框架就是這樣。我們先來看下他的過程。首先,在mem_pool_init()函數中,他先分配512個不連續的student對象。每分配出來一個就把它加入到free鏈表中,初始化完成后內存池大概是這樣的

接下來就是從內存池中取出一個對象get_data()。函數先去判斷是否有空閑的對象,有則直接分配,否則再向系統獲取一"塊"大的內存。調用一次后的內存池大概是這樣的

釋放對象,再把對象加入到Free鏈表中。
以上就是過程的簡單分析,下面我們來看看他的缺點。
第一,內存不是連續的,容易產生碎片
第二,一個類型就得寫一個這樣的內存池,很麻煩
第三,為了構建這個內存池,每個沒對象必須加上一個prev,next指針
好了,我們來優化一下它。我們重新定義下我們的結構體
union student
{
    
int index;
    
struct
    {
        
char name[32];
        
byte sex;
    }s;
};

static struct mem_pool
{
    
//該下標用來記錄空閑節點
    int free;
    
//內存池
    union student *mem;
    
//已分配結點個數
    size_t alloc_cnt;
}s_mem_pool;

//分配內存塊的函數
bool mem_pool_resize(size_t size)
{
    size_t new_size 
= s_mem_pool.alloc_cnt+size;
    union student 
*tmp = (union student *)realloc(s_mem_pool.mem,new_size*sizeof(union student));
    
if ( !tmp )
        
return false;
        
    memset(tmp
+s_mem_pool.alloc_cnt,0,size*sizeof(union student));
    size_t i 
= s_mem_pool.alloc_cnt;
    
for ( ;i < new_size - 1;++i )
    {
        tmp[i].index 
= i + 1;
    }
    
    tmp[i].index 
= -1;
    s_mem_pool.free 
= s_mem_pool.alloc_cnt;
    s_mem_pool.mem 
= tmp;
    s_mem_pool.alloc_cnt 
= new_size;
    
    
return true;
}

#define MEM_INIT_SIZE    512  
#define MEM_INC_SIZE    256
//初始化函數
bool mem_pool_init()
{
    
if ( !mem_pool_resize(MEM_INIT_SIZE) )
        
return false;
        
    
return true;
}

union student 
*get_data()
{
    
if ( s_mem_pool.free == -1 )
    {
        
if ( !mem_pool_resize(MEM_INC_SIZE) )
            
return NULL;
    }
    
    union student 
*ret = s_mem_pool.mem+s_mem_pool.free;
    s_mem_pool.free 
= ret->index;
    
return ret;
}

void free_data(union student *p)
{
    
if ( !p )
        
return;
    
    p
->index = s_mem_pool.free;
    s_mem_pool.free 
= p - s_mem_pool.mem;
}
我們來看看改進了些什么。第一student改成了聯合體,這主要是為了不占用額外的內存,也就是我們上面所說的第三個缺點,第二,我們使用了realloc函數,這樣我們可以使我們分配出來的內存是連續的。我們初始化的時候多了一個for循環,這是為了記錄空閑對象的下標,當我們取出一個對象時,free可以立刻知道下一個空閑對象的位置,釋放的時候,對象先記錄free此時的值,接著再把free賦值成該對象在數組的下標,這樣就完成了回收工作。
我們繼續分析這段代碼,問題在realloc函數上,如果我們的s_mem_pool.mem已經很大了,在realloc的時候我們都知道,先要把原來的數據做一次拷貝,所以如果數據量很大的情況下做一次拷貝,是會消耗性能的。那這里有沒有好的辦法呢,我們進一步優化
思路大概是這樣
初始化

再次分配的時候,我們只需要重新分配新的內存單元,而不需要拷貝之前的內存單元。

因此基于此思路,我們修改我們的代碼
#include <stdio.h>
#include 
<stdlib.h>

struct student
{
    
int index;

    
char name[32];
    
byte sex;
};

static struct mem_pool
{
    
//該下標用來記錄空閑節點
    int free;
    
//內存池
    struct student **mem;
    
//已分配塊個數
    size_t block_cnt;
}s_mem_pool;

#define BLOCK_SIZE        256        //每塊的大小
//分配內存塊的函數
bool mem_pool_resize(size_t block_size)
{
    size_t new_cnt 
= s_mem_pool.block_cnt + block_size;
    
struct student **tmp = (struct student **)realloc(s_mem_pool.mem,new_size*sizeof(struct student *));
    
if ( !tmp )
        
return false;
        
    memset(tmp
+s_mem_pool.block_cnt,0,size*sizeof(struct student*));
    
for ( size_t i = s_mem_pool.block_cnt;i < new_cnt;++i )
    {
        tmp[i] 
= (struct student *)calloc(BLOCK_SIZE,sizeof(struct student));
        
if ( !tmp[i] )
            
return false;
            
        size_t j 
= 0;
        
for(;j < BLOCK_SIZE - 1;++j )
        {
            tmp[i][j].index 
= i*BLOCK_SIZE+j+1;
        }
        
        
if ( i != new_cnt-1 )
            tmp[i][j].index 
= (i+1)*BLOCK_SIZE;
        
else
            tmp[i][j].index 
= -1;
    }
    
    s_mem_pool.free 
= s_mem_pool.alloc_cnt*BLOCK_SIZE;
    s_mem_pool.mem 
= tmp;
    s_mem_pool.block_cnt 
= new_cnt;
    
    
return true;
}
 
#define MEM_INC_SIZE    10
//初始化函數
bool mem_pool_init()
{
    
if ( !mem_pool_resize(MEM_INIT_SIZE) )
        
return false;
        
    
return true;
}

struct student *get_data()
{
    
if ( s_mem_pool.free == -1 )
    {
        
if ( !mem_pool_resize(MEM_INC_SIZE) )
            
return NULL;
    }
    
    
struct student *ret = s_mem_pool.mem[s_mem_pool.free/BLOCK_SIZE]+s_mem_pool.free%BLOCK_SIZE;
    
int pos = s_mem_pool.free;
    s_mem_pool.free 
= ret->index;
    ret
->index = pos;
    
return ret;
}

void free_data(struct student *p)
{
    
if ( !p )
        
return;
    
    
int pos = p->index;
    p
->index = s_mem_pool.free;
    s_mem_pool.free 
= pos;
}
這里不一樣的地方主要在mem_pool_resize函數中,mem變成了2級指針,每次realloc的時候只需要分配指針數組的大小,無須拷貝對象,這樣可以提高效率,但是為了在釋放的時候把對象放回該放的位置,我們這里在結構體里加入了index變量,記錄它的下標。在內存池里,它表示下個空閑對象的下標,在內存池外,它表示在內存池中的下標。總的來說滿足了一個需求,卻又帶來了新的問題,有沒有更好的方法呢,答案是肯定,不過今天先寫到這里,明天繼續。
posted on 2012-07-19 11:41 梨樹陽光 閱讀(3556) 評論(2)  編輯 收藏 引用 所屬分類: C

FeedBack:
# re: 淺談內存池幾種設計方式[未登錄]
2012-07-20 07:55 | 123
上圖談思路就行了,上代碼也是直接拖過不看的。
共享代碼可以直接給個下載鏈接  回復  更多評論
  
# re: 淺談內存池幾種設計方式
2012-07-23 09:27 | egmkang
額....這年頭,還真有人去設計內存池啊
有沒有試過tcmalloc和jemalloc,用自己的內存池和別人的內存分配器比一下,試試  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久影音先锋| 欧美日韩不卡在线| 久久米奇亚洲| aa级大片欧美| 在线日韩精品视频| 国产精品一区二区在线观看不卡 | 国内精品久久久久影院色| 美女黄毛**国产精品啪啪| 亚洲精品国产精品久久清纯直播| 国产麻豆成人精品| 国产精品欧美久久| 欧美视频在线看| 欧美三级午夜理伦三级中文幕 | 亚洲欧美在线磁力| 好吊色欧美一区二区三区视频| 欧美亚男人的天堂| 国产精品户外野外| 午夜精品一区二区三区在线视 | 欧美有码视频| 久久精品日韩一区二区三区| 欧美一区午夜精品| 久久精品国产免费观看| 久久久精品2019中文字幕神马| 欧美高清在线| 欧美精品在线播放| 狠狠入ady亚洲精品经典电影| 亚洲国产色一区| 先锋影音一区二区三区| 亚洲国产高清一区| 亚洲一品av免费观看| 美女999久久久精品视频| 国产精品成人va在线观看| 亚洲电影天堂av| 久久久久久久久久久久久女国产乱 | 在线免费观看视频一区| 亚洲综合精品四区| 欧美aⅴ99久久黑人专区| 亚洲最新在线| 欧美jjzz| 在线观看中文字幕不卡| 午夜精品久久久久久久99樱桃| 欧美激情影音先锋| 久久久久久黄| 国产午夜精品一区二区三区视频| 99综合在线| 亚洲丰满在线| 久久亚洲二区| 国产一区二区观看| 欧美在线观看视频一区二区| 一区二区av| 欧美性生交xxxxx久久久| 亚洲精品日韩精品| 欧美成人dvd在线视频| 国产精品日韩在线| 亚洲一区成人| 一区二区三区波多野结衣在线观看| 久久综合99re88久久爱| 国产一区二区三区黄| 欧美一级片在线播放| 夜夜爽99久久国产综合精品女不卡| 欧美成人影音| 99国产精品99久久久久久| 最新亚洲一区| 欧美二区不卡| 中日韩男男gay无套| 日韩一区二区电影网| 欧美女人交a| 亚洲一区二区三区777| 国产精品99久久久久久久女警| 欧美日韩亚洲另类| 欧美亚洲尤物久久| 欧美中文字幕| 亚洲国产网站| 亚洲看片网站| 国产精品午夜国产小视频| 欧美一区免费视频| 久久精品国产亚洲高清剧情介绍| 国产夜色精品一区二区av| 久久一二三四| 裸体歌舞表演一区二区| 亚洲精品视频在线观看免费| 99视频一区二区三区| 国产欧美精品国产国产专区| 久久精视频免费在线久久完整在线看| 亚洲欧美视频在线观看视频| 一区免费在线| 亚洲成人自拍视频| 欧美亚州一区二区三区 | 欧美三级午夜理伦三级中文幕| 亚洲一区二区三区四区视频 | 欧美激情视频一区二区三区在线播放| 久久亚洲国产精品一区二区| 亚洲日本无吗高清不卡| 一区二区三区导航| 永久域名在线精品| 日韩视频一区二区三区| 国产午夜精品一区二区三区欧美 | 亚洲欧美日韩一区二区三区在线| 亚洲欧美成人一区二区三区| 一区视频在线| 亚洲天堂av高清| 伊人久久av导航| 亚洲一区二区在线免费观看视频| 在线日本成人| 亚洲制服丝袜在线| 亚洲电影在线看| 亚洲国产成人tv| 一区二区三区精品国产| 在线成人国产| 亚洲一区二区精品在线| 亚洲大胆人体在线| 亚洲欧美国产高清va在线播| 亚洲精品看片| 久久久噜噜噜久久中文字幕色伊伊 | 久久久久久久综合日本| 亚洲在线一区二区| 久久野战av| 久久嫩草精品久久久精品| 国产精品久久久久aaaa樱花 | 欧美专区日韩视频| 欧美午夜a级限制福利片| 欧美国产亚洲精品久久久8v| 国内精品久久久久影院优| 亚洲一区久久久| 亚洲免费一在线| 欧美日韩在线视频一区| 亚洲人成啪啪网站| 亚洲免费观看高清在线观看| 久久永久免费| 欧美承认网站| 亚洲福利专区| 免费日韩视频| 亚洲国产裸拍裸体视频在线观看乱了| 国内精品久久久久久久97牛牛| 一区二区欧美亚洲| 亚洲手机视频| 国产精品国产一区二区| 亚洲天堂av高清| 欧美亚洲在线视频| 国产欧美日韩视频在线观看 | 一道本一区二区| 欧美暴力喷水在线| 亚洲电影免费观看高清完整版在线观看 | 欧美精品v日韩精品v韩国精品v | 久久蜜桃av一区精品变态类天堂| 国产女主播在线一区二区| 国产麻豆91精品| 亚洲男人影院| 久久精品最新地址| 国产亚洲精品一区二区| 久久aⅴ国产紧身牛仔裤| 国产精品一区二区久久久久| 亚洲特黄一级片| 久久超碰97人人做人人爱| 国产亚洲精品bv在线观看| 欧美在线观看www| 蜜臀av在线播放一区二区三区| 伊人久久久大香线蕉综合直播| 久久嫩草精品久久久精品一| 欧美国产一区二区在线观看| 亚洲精品自在在线观看| 欧美日韩福利| 亚洲天堂av图片| 久久久久99| 亚洲人成免费| 国产精品久久久久久久久免费桃花 | 欧美激情女人20p| 亚洲精品字幕| 国产精品日韩精品欧美在线| 久久精品亚洲国产奇米99| 亚洲高清在线观看| 亚洲欧美日韩综合一区| 亚洲第一中文字幕| 欧美性大战久久久久| 欧美一区二区黄| 91久久精品国产91性色tv| 午夜视频一区| 亚洲激情女人| 国产精品美女久久久久久久| 麻豆精品在线播放| 亚洲一区国产| 亚洲二区在线观看| 久久精品国产亚洲一区二区三区| 亚洲欧洲精品一区| 国产欧美在线视频| 欧美伦理a级免费电影| 欧美一区二区三区婷婷月色 | 免费成人在线观看视频| 亚洲欧美福利一区二区| 亚洲精品国精品久久99热| 欧美在线黄色| 亚洲宅男天堂在线观看无病毒| 最新成人在线| 在线观看一区视频| 国产伦精品一区二区三区四区免费| 欧美精品97| 欧美高清在线视频| 女同性一区二区三区人了人一| 亚洲欧美另类在线| 亚洲天堂免费观看|