• <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>
            posts - 15,comments - 21,trackbacks - 0
                  寫(xiě)服務(wù)器的,通常會(huì)涉及到內(nèi)存池的東西,自己在這方面也看了寫(xiě)了一些東西,有些體會(huì),寫(xiě)出來(lái)跟大家分享下。
                  內(nèi)存池基本包含以下幾個(gè)東西,第一,初始化。第二,分配內(nèi)存。第三,回收內(nèi)存。所謂初始化,就是在服務(wù)器啟動(dòng)的時(shí)候,或者第一次需要內(nèi)存的時(shí)候,系統(tǒng)分配很大的一塊內(nèi)存,方便之后的使用。分配內(nèi)存,就是從內(nèi)存池中取出需要的內(nèi)存給外部使用,當(dāng)然這里需要考慮的是當(dāng)內(nèi)存池中沒(méi)有內(nèi)存可分配時(shí)候的處理。回收內(nèi)存,簡(jiǎn)單來(lái)說(shuō),就是外面對(duì)象生命期結(jié)束了,將分配出去的內(nèi)存回收入內(nèi)存池中。好了簡(jiǎn)單概念就說(shuō)完了,我們先來(lái)看一種最簡(jiǎn)單的設(shè)計(jì)方式。
            //為了方便描述,這里附上幾個(gè)簡(jiǎn)單的鏈表操作宏
            #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
            {
                  //該指針用來(lái)記錄空閑節(jié)點(diǎn)
                  
            struct student *free;
                  //該變量記錄分配結(jié)點(diǎn)個(gè)數(shù)
                  size_t alloc_cnt;
            }s_mem_pool;

            //分配內(nèi)存“塊”的函數(shù)
            bool mem_pool_resize(size_t size)
            {
                  //該函數(shù)創(chuàng)建size個(gè)不連續(xù)的對(duì)象,把他們通過(guò)鏈表的方式加入到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
            //初始化函數(shù)
            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)
            }
            好了最簡(jiǎn)單的內(nèi)存池的大致框架就是這樣。我們先來(lái)看下他的過(guò)程。首先,在mem_pool_init()函數(shù)中,他先分配512個(gè)不連續(xù)的student對(duì)象。每分配出來(lái)一個(gè)就把它加入到free鏈表中,初始化完成后內(nèi)存池大概是這樣的

            接下來(lái)就是從內(nèi)存池中取出一個(gè)對(duì)象get_data()。函數(shù)先去判斷是否有空閑的對(duì)象,有則直接分配,否則再向系統(tǒng)獲取一"塊"大的內(nèi)存。調(diào)用一次后的內(nèi)存池大概是這樣的

            釋放對(duì)象,再把對(duì)象加入到Free鏈表中。
            以上就是過(guò)程的簡(jiǎn)單分析,下面我們來(lái)看看他的缺點(diǎn)。
            第一,內(nèi)存不是連續(xù)的,容易產(chǎn)生碎片
            第二,一個(gè)類(lèi)型就得寫(xiě)一個(gè)這樣的內(nèi)存池,很麻煩
            第三,為了構(gòu)建這個(gè)內(nèi)存池,每個(gè)沒(méi)對(duì)象必須加上一個(gè)prev,next指針
            好了,我們來(lái)優(yōu)化一下它。我們重新定義下我們的結(jié)構(gòu)體
            union student
            {
                
            int index;
                
            struct
                {
                    
            char name[32];
                    
            byte sex;
                }s;
            };

            static struct mem_pool
            {
                
            //該下標(biāo)用來(lái)記錄空閑節(jié)點(diǎn)
                int free;
                
            //內(nèi)存池
                union student *mem;
                
            //已分配結(jié)點(diǎn)個(gè)數(shù)
                size_t alloc_cnt;
            }s_mem_pool;

            //分配內(nèi)存塊的函數(shù)
            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
            //初始化函數(shù)
            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;
            }
            我們來(lái)看看改進(jìn)了些什么。第一student改成了聯(lián)合體,這主要是為了不占用額外的內(nèi)存,也就是我們上面所說(shuō)的第三個(gè)缺點(diǎn),第二,我們使用了realloc函數(shù),這樣我們可以使我們分配出來(lái)的內(nèi)存是連續(xù)的。我們初始化的時(shí)候多了一個(gè)for循環(huán),這是為了記錄空閑對(duì)象的下標(biāo),當(dāng)我們?nèi)〕鲆粋€(gè)對(duì)象時(shí),free可以立刻知道下一個(gè)空閑對(duì)象的位置,釋放的時(shí)候,對(duì)象先記錄free此時(shí)的值,接著再把free賦值成該對(duì)象在數(shù)組的下標(biāo),這樣就完成了回收工作。
            我們繼續(xù)分析這段代碼,問(wèn)題在realloc函數(shù)上,如果我們的s_mem_pool.mem已經(jīng)很大了,在realloc的時(shí)候我們都知道,先要把原來(lái)的數(shù)據(jù)做一次拷貝,所以如果數(shù)據(jù)量很大的情況下做一次拷貝,是會(huì)消耗性能的。那這里有沒(méi)有好的辦法呢,我們進(jìn)一步優(yōu)化
            思路大概是這樣
            初始化

            再次分配的時(shí)候,我們只需要重新分配新的內(nèi)存單元,而不需要拷貝之前的內(nèi)存單元。

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

            struct student
            {
                
            int index;

                
            char name[32];
                
            byte sex;
            };

            static struct mem_pool
            {
                
            //該下標(biāo)用來(lái)記錄空閑節(jié)點(diǎn)
                int free;
                
            //內(nèi)存池
                struct student **mem;
                
            //已分配塊個(gè)數(shù)
                size_t block_cnt;
            }s_mem_pool;

            #define BLOCK_SIZE        256        //每塊的大小
            //分配內(nèi)存塊的函數(shù)
            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
            //初始化函數(shù)
            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函數(shù)中,mem變成了2級(jí)指針,每次realloc的時(shí)候只需要分配指針數(shù)組的大小,無(wú)須拷貝對(duì)象,這樣可以提高效率,但是為了在釋放的時(shí)候把對(duì)象放回該放的位置,我們這里在結(jié)構(gòu)體里加入了index變量,記錄它的下標(biāo)。在內(nèi)存池里,它表示下個(gè)空閑對(duì)象的下標(biāo),在內(nèi)存池外,它表示在內(nèi)存池中的下標(biāo)。總的來(lái)說(shuō)滿(mǎn)足了一個(gè)需求,卻又帶來(lái)了新的問(wèn)題,有沒(méi)有更好的方法呢,答案是肯定,不過(guò)今天先寫(xiě)到這里,明天繼續(xù)。
            posted on 2012-07-19 11:41 梨樹(shù)陽(yáng)光 閱讀(3520) 評(píng)論(2)  編輯 收藏 引用 所屬分類(lèi): C

            FeedBack:
            # re: 淺談內(nèi)存池幾種設(shè)計(jì)方式[未登錄](méi)
            2012-07-20 07:55 | 123
            上圖談思路就行了,上代碼也是直接拖過(guò)不看的。
            共享代碼可以直接給個(gè)下載鏈接  回復(fù)  更多評(píng)論
              
            # re: 淺談內(nèi)存池幾種設(shè)計(jì)方式
            2012-07-23 09:27 | egmkang
            額....這年頭,還真有人去設(shè)計(jì)內(nèi)存池啊
            有沒(méi)有試過(guò)tcmalloc和jemalloc,用自己的內(nèi)存池和別人的內(nèi)存分配器比一下,試試  回復(fù)  更多評(píng)論
              
            久久99国产精品久久99果冻传媒| 亚洲国产香蕉人人爽成AV片久久| 久久亚洲国产中v天仙www| 久久九色综合九色99伊人| 超级碰碰碰碰97久久久久| 久久A级毛片免费观看| 久久精品成人| 国产精品久久久久久搜索| 青青草国产97免久久费观看| 久久亚洲精品无码AV红樱桃| 人妻少妇精品久久| 久久亚洲国产精品一区二区| 亚洲国产美女精品久久久久∴| 精品久久综合1区2区3区激情 | 久久久久一级精品亚洲国产成人综合AV区| 亚洲伊人久久综合影院| 成人国内精品久久久久影院VR| 久久久久成人精品无码中文字幕| 一级做a爰片久久毛片免费陪| 99久久99久久精品国产| 精品熟女少妇av免费久久| 久久久久人妻一区二区三区| 看全色黄大色大片免费久久久| 久久综合综合久久狠狠狠97色88| 色婷婷综合久久久久中文| 久久天天躁狠狠躁夜夜躁2014| 久久亚洲天堂| 亚洲成av人片不卡无码久久| 精品熟女少妇aⅴ免费久久| 一级做a爰片久久毛片16| 激情伊人五月天久久综合| 亚洲精品无码久久千人斩| 精品久久久无码21p发布| 色天使久久综合网天天| 狠狠色丁香婷婷久久综合| 99久久综合国产精品免费| 亚洲人成电影网站久久| 久久久久久伊人高潮影院| 久久精品一本到99热免费| 中文字幕久久久久人妻| 精品久久久久久成人AV|