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

隨筆-91  評論-137  文章-0  trackbacks-0
內存池的作用:
減少內存碎片,提高性能。

首先不得不提的是Win32和x64中對于指針的長度是不同的,在Win32中一個指針占4字節,而在x64中一個指針占8字節。也正是不清楚這一點,當我在x64中將指針作為4字節修改造成其他數據異常。

首先我們先來定義三個宏
            #define ALIGN     sizeof(void*)
            #define MAX_BYTES 128
            #define MAX_COUNT (MAX_BYTES / ALIGN)
正如前面所說的,為了兼容Win32與x64應此我們將要申請的內存按void*的大小來對齊。正如前面所說的,我們認為小于128字節的內存為小內存,會產生內存碎片,應此在申請時應該勁量申請一塊較大的內存而將其中的一小塊分配給他。

然后讓我們來看一下內存池中的成員變量
            struct obj
            {
                obj* next;
            };

            struct block
            {
                block* next;
                void*  data;
            };

            obj*   chunk_list[MAX_COUNT];
            size_t chunk_count;
            block* free_list;
這里使用obj結構來存儲已釋放內存的列表,這樣做的好處是可以更節省內存。在Win32中使用這塊內存的前4字節來指向下一個節點,而在x64中使用這塊內存的前8字節來指向下一個節點。
chunk_list:保存通過deallocate或refill中釋放或是新申請的內存塊列表,deallocate和refill將會在下文中介紹。
chunk_count:內存塊列表中已有的內存塊數量。
free_list:保存了通過malloc申請內存塊的鏈表。

下面我們來看一下內存池的構造函數與析構函數
            MemoryPool() : free_list(0), chunk_count(0)
            {
                for(int i = 0; i < MAX_COUNT; ++i) chunk_list[i] = 0;
            }

            ~MemoryPool()
            {
                block* current = free_list;
                while(current)
                {
                    block* next = current->next;
                    free(current->data);
                    free(current);
                    current = next;
                }
            }
構造函數中初始化free_list和chunk_count為0,并初始化chunk_list為一個空列表。而在析構函數中我們必須釋放每一塊通過malloc申請的大內存塊。

接下來是內存的申請
            template <typename T>
            T* allocate(size_t n, void(*h)(size_t))
            {
                if(n == 0) return 0;
                if(n > MAX_BYTES)
                {
                    T* p = (T*)malloc(n);
                    while(p == 0)
                    {
                        h(n);
                        p = (T*)malloc(n);
                    }
                    return p;
                }
                const int i = INDEX(ROUND_UP(n));
                obj* p = chunk_list[i];
                if(p == 0)
                {
                    return refill<T>(i, h);
                }
                chunk_list[i] = p->next;
                return reinterpret_cast<T*>(p);
            }
值得注意的是,在調用時必須傳入一個函數指針作為參數,當malloc申請內存失敗時會去調用這個函數來釋放出足夠多的內存空間。當要申請的內存大小超過128字節時,調用默認的malloc為其申請內存。否則先查找列表中是否還有足夠的空間分配給它,若已沒有足夠的空間分配給它,則調用refill申請一塊大內存。

然后是內存釋放函數deallocate
            template <typename T>
            void deallocate(T* p, size_t n)
            {
                if(p == 0) return;
                if(n > MAX_BYTES)
                {
                    free(p);
                    return;
                }
                const int i = INDEX(ROUND_UP(n));
                reinterpret_cast<obj*>(p)->next = chunk_list[i];
                chunk_list[i] = reinterpret_cast<obj*>(p);
            }
值得注意的是在釋放時必須給出這塊內存塊的大小。若這塊內存大于128字節時,調用默認的free函數釋放掉這塊內存。否則將其加到對應的chunk_list列表內。

然后是調整內存塊大小函數reallocate
            template <typename T>
            T* reallocate(T* p, size_t old_size, size_t new_size, void(*h)(size_t))
            {
                if(old_size > MAX_BYTES && new_size > MAX_BYTES)
                {
                    return realloc(p, new_size);
                }
                if(ROUND_UP(old_size) == ROUND_UP(new_size)) return p;
                T* result = allocate<T>(new_size, h);
                const size_t copy_size = new_size > old_size ? old_size : new_size;
                memcpy(result, p, copy_size);
                deallocate<T>(p, old_size);
                return result;
            }
參數中必須給出這塊內存的原始大小和要調整后的大小,同時也必須給出當內存不足時的釋放函數的指針。若舊內存塊和新內存塊的大小都大于128字節時,調用默認的realloc函數重新分配內存。否則先按調整后的大小申請一塊內存,并把原來的內容拷貝過來,最后釋放掉原來的內存塊。這里并不建議使用這個函數,而是手動的去重新申請內存并拷貝釋放。

然后來看4個非常簡單的計算函數
            inline size_t ROUND_UP(size_t bytes)const
            {
                return (bytes + ALIGN - 1) & ~(ALIGN - 1);
            }

            inline size_t ROUND_DOWN(size_t bytes)const
            {
                return bytes & ~(ALIGN - 1);
            }

            inline int INDEX(size_t bytes)const
            {
                return (bytes + ALIGN - 1) / ALIGN - 1;
            }

            inline size_t obj_count(int i)const
            {
                size_t result = 0;
                obj* current = chunk_list[i];
                while(current)
                {
                    ++result;
                    current = current->next;
                }
                return result;
            }
前3個用于內存對齊和計算索引,最后一個用于獲取一在空閑列表內一個內存塊的數量。

然后是refill函數,用于在沒有空閑內存塊時申請一塊大內存塊
            template <typename T>
            T* refill(int i, void(*h)(size_t))
            {
                const int count = 20;
                const int preSize = (i + 1) * ALIGN;
                char* p = (char*)malloc(preSize * count);
                while(p == 0)
                {
                    h(preSize * count);
                    p = (char*)malloc(preSize * count);
                }
                block* pBlock = (block*)malloc(sizeof(block));
                while(pBlock == 0)
                {
                    h(sizeof(block));
                    pBlock = (block*)malloc(sizeof(block));
                }
                pBlock->data = p;
                pBlock->next = free_list;
                free_list = pBlock;
                obj* current = (obj*)(p + preSize);
                for(int j = 0; j < count - 1; ++j)
                {
                    current->next = chunk_list[i];
                    chunk_list[i] = current;
                    current = (obj*)((char*)current + preSize);
                }
                chunk_count += count - 1;
                rebalance();
                return reinterpret_cast<T*>(p);
            }
首先申請一個大內存塊,然后將這塊申請到的內存塊放入free_list鏈表內,最后組織起chunk_list中對應內存卡塊的鏈表,然后重新調整chunk_list列表,最后將申請到的內存塊返回。

最后來看一下調整函數rebalance
            void rebalance()
            {
                for(int i = MAX_COUNT - 1; i > 0; --i)
                {
                    const size_t avge = chunk_count / MAX_COUNT;
                    size_t count = obj_count(i);
                    if(count > avge)
                    {
                        const int preSize = ROUND_DOWN((i + 1) * ALIGN / 2);
                        const int j = INDEX(preSize);
                        for(int k = count; k > avge; --k)
                        {
                            obj* chunk = chunk_list[i];
                            chunk_list[i] = chunk_list[i]->next;
                            if(i % 2 == 1)
                            {
                                chunk->next = (obj*)((char*)chunk + preSize);
                                chunk->next->next = chunk_list[j];
                                chunk_list[j] = chunk;
                            }
                            else
                            {
                                chunk->next = chunk_list[j];
                                chunk_list[j] = chunk;
                                obj* next = (obj*)((char*)chunk + preSize);
                                next->next = chunk_list[j + 1];
                                chunk_list[j + 1] = next;
                            }
                            ++chunk_count;
                        }
                    }
                }
            }
這里從后至前查看對應內存塊空閑鏈表的長度,若超過平均數量,則將其切分為2塊較小的內存塊放入對應的鏈表內。這樣做的好處是可以形成一個金字塔形的分布狀況,既越小的內存塊大小擁有的節點數量越多,正如本文開頭所說,使用內存池是為了解決在申請小塊內存時造成的內存碎片。

至此,內存池的講解已完成,完整的代碼請到http://qlanguage.codeplex.com下載
posted on 2012-07-14 18:40 lwch 閱讀(2454) 評論(1)  編輯 收藏 引用 所屬分類: STL

評論:
# re: 山寨STL實現之內存池 2013-01-19 22:58 | eryar
Good,
Marked!  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久精品国产99精品国产亚洲性色| 玖玖综合伊人| 欧美日韩国产综合一区二区| 国产午夜精品久久久| 性色av一区二区三区在线观看| 一区二区三区久久精品| 亚洲人成小说网站色在线| 久热精品视频在线| 亚洲欧洲日韩综合二区| 日韩亚洲精品电影| 国产精品永久免费视频| 欧美亚洲一区| 久久精品人人做人人爽| 亚洲国产午夜| 日韩亚洲精品电影| 国产亚洲免费的视频看| 免费久久精品视频| 欧美日韩美女在线观看| 欧美一站二站| 葵司免费一区二区三区四区五区| 欧美日韩一卡二卡| 欧美一区二区三区日韩| 久久久精品久久久久| 亚洲经典视频在线观看| 在线亚洲欧美| 1000部国产精品成人观看| 亚洲精品字幕| 国产在线精品一区二区中文| 欧美激情91| 国产精品色午夜在线观看| 久久久久久婷| 欧美高清影院| 久久综合福利| 国产精品v亚洲精品v日韩精品| 在线观看亚洲精品| 夜夜嗨av色一区二区不卡| 国产日韩亚洲欧美综合| 亚洲欧洲日本mm| 韩国精品一区二区三区| 中文精品视频| 亚洲精品一品区二品区三品区| 久久夜色精品| 国产精品久久久一区二区三区| 亚洲人成亚洲人成在线观看图片 | 欧美日本一区二区高清播放视频| 国产日韩欧美不卡| 亚洲国产精品成人精品 | 玖玖精品视频| 国产精品久久久久一区| 91久久综合亚洲鲁鲁五月天| 激情久久中文字幕| 欧美一区二区三区免费视频 | 久久精品久久综合| 亚洲在线不卡| 欧美日韩亚洲网| 欧美激情综合色| 国产在线乱码一区二区三区| 亚洲女ⅴideoshd黑人| 亚洲视频在线观看三级| 欧美激情综合色| 欧美成人精品h版在线观看| 国产欧美日韩三级| 亚洲欧美日本日韩| 欧美在线观看视频一区二区| 国产精品久99| 麻豆成人91精品二区三区| 欧美视频一区在线| 99热在线精品观看| 99精品国产一区二区青青牛奶| 亚洲风情在线资源站| 国产亚洲精品bt天堂精选| 亚洲一区国产视频| 亚洲免费高清视频| 免费在线播放第一区高清av| 99热这里只有精品8| 欧美连裤袜在线视频| 欧美大片在线看| 1769国产精品| 久久久精品性| 久久手机精品视频| 国产亚洲精品高潮| 性伦欧美刺激片在线观看| 性欧美xxxx视频在线观看| 欧美日韩在线一区二区| 亚洲精品乱码久久久久久日本蜜臀 | 99国产精品久久久久老师| 欧美在线免费播放| 久久久99爱| 国产精品免费区二区三区观看| 久久久天天操| 国内外成人在线视频| 欧美在线播放一区二区| 久久久欧美精品sm网站| 狠狠色丁香婷综合久久| 久久综合伊人77777尤物| 欧美激情第8页| 日韩视频一区二区三区| 欧美精品福利视频| 美日韩精品视频免费看| 韩国一区电影| 免费观看久久久4p| 亚洲激情在线观看视频免费| 一区二区高清视频在线观看| 欧美日韩在线大尺度| 亚洲一区二区三区激情| 性8sex亚洲区入口| 精品动漫一区| 久久久久久久欧美精品| 99re热这里只有精品免费视频| 伊人成人开心激情综合网| 久久最新视频| 亚洲精品一区二区三区蜜桃久| 国产小视频国产精品| 久久久亚洲高清| 久久久久在线| 91久久黄色| 欧美日韩国产专区| 午夜一区二区三区不卡视频| 91久久精品www人人做人人爽 | 欧美一区二区三区男人的天堂| 91久久中文| 国产精品拍天天在线| 久久久亚洲国产天美传媒修理工 | 午夜精品999| 米奇777超碰欧美日韩亚洲| 夜夜嗨av一区二区三区网站四季av | 亚洲第一黄色| 欧美吻胸吃奶大尺度电影| 久久久成人精品| 一本久道综合久久精品| 免费在线观看日韩欧美| 午夜精品福利视频| 亚洲精品欧洲| 激情六月综合| 国产精品入口66mio| 欧美电影资源| 欧美 日韩 国产在线| 亚洲女同精品视频| 亚洲国产成人在线播放| 欧美诱惑福利视频| 亚洲精品在线看| 国产精品稀缺呦系列在线| 欧美日韩国产三区| 你懂的亚洲视频| 久久精品亚洲一区| 欧美影院久久久| 亚洲欧美国产制服动漫| 日韩午夜在线电影| 91久久国产综合久久91精品网站| 日韩亚洲欧美高清| 国产精品午夜久久| 欧美日韩亚洲国产精品| 欧美福利视频| 毛片精品免费在线观看| 久久久久国色av免费看影院| 欧美一区久久| 99亚洲一区二区| 亚洲黄色尤物视频| 亚洲国产欧美一区| 欧美激情在线观看| 欧美韩日一区二区三区| 欧美电影打屁股sp| 欧美国产日韩二区| 99国产精品国产精品毛片| 亚洲人妖在线| 亚洲日韩成人| 亚洲免费高清| 中文亚洲视频在线| 亚洲综合国产| 一区二区精品在线观看| 欧美亚洲免费高清在线观看| 亚洲影院在线观看| 欧美在线视频一区| 久久九九99视频| 美日韩在线观看| 欧美成人在线网站| 久久精品夜色噜噜亚洲aⅴ| 欧美激情一区二区三区蜜桃视频| 亚洲一二三四区| 欧美一区二区视频网站| 久久久久久久久久码影片| 欧美大片在线观看| 欧美视频在线一区| 欧美性猛交视频| 国内精品亚洲| 亚洲人成人99网站| 亚洲一区日韩| 欧美制服丝袜第一页| 欧美成人午夜| 一区二区三区四区五区视频 | 国产精品福利在线观看网址| 国产精品麻豆va在线播放| 国产区精品视频| 国产亚洲精品bt天堂精选| 亚洲毛片在线免费观看| 性色av一区二区三区在线观看| 亚洲国产精品嫩草影院| 亚洲一区二区三区高清不卡| 久久久午夜视频| 最新国产乱人伦偷精品免费网站|