《STL源碼剖析》筆記:空間配置器

在書中介紹了有2個(gè)空間配置器:

  • 第一個(gè)是適合直接用的malloc/free钾菊,簡單包裝了下蜀肘,并實(shí)現(xiàn)了類似C++ new-handler機(jī)制蔓钟。
  • 第二個(gè)用的是一個(gè)建立在一個(gè)內(nèi)存池和free_list上面的次級(jí)配置器,實(shí)現(xiàn)了更靈活的內(nèi)存管理搂捧。
一級(jí)配置器
二級(jí)配置器

二級(jí)配置器多了些機(jī)制驮俗,避免了太多小額區(qū)塊造成的內(nèi)存碎片。整體做法是:如果區(qū)塊足夠大允跑,超128bytes 時(shí)王凑,就移交第一級(jí)配置器處理搪柑,當(dāng)區(qū)塊小于128bytes時(shí),則以內(nèi)存池管理索烹。

二級(jí)配置器整體配置如圖:

二級(jí)空間配置器.jpg

內(nèi)存池就是從堆中申請(qǐng)的大塊的內(nèi)存工碾,負(fù)責(zé)填充free_list。內(nèi)存池直接由malloc分配术荤,用2個(gè)指針表示,start_free指針表示當(dāng)前內(nèi)存池剩余內(nèi)存的起始地址每篷。

內(nèi)存池.jpg

free_list

union obj 
{
    union obj *free_list_link;
    char client_data[1];    // 沒什么用
};

enum {  _ALIGN = 8  };    // 小型區(qū)塊下限
enum {  _MAX_BYTES = 128  };    // 小型區(qū)塊上限
enum {  _NFREELISTS = _MAX_BYTES / _ALIGN  };  // free_list 個(gè)數(shù)

free_list是指針數(shù)組瓣戚。每一個(gè)數(shù)組槽內(nèi)指向的是一個(gè)由指定大小的內(nèi)存塊連接起來的list〗苟粒客戶申請(qǐng)內(nèi)存子库,就將其中相應(yīng)的內(nèi)存從list"拔下",客戶歸還內(nèi)存則就內(nèi)存插入相應(yīng)的list中矗晃。

free_list.jpg

空間配置器

class alloc 
{
    private:
        static obj* free_list[_NFREELISTS];      // obj數(shù)組
    private:
        static char *start_free;    // 內(nèi)存池起始位置
        static char *end_free;      // 內(nèi)存池結(jié)束位置
        static size_t heap_size;
    private:
        /*  將bytes上調(diào)至8的倍數(shù)  */
        static size_t ROUND_UP(size_t bytes) 
        {  
            return (((bytes) + _ALIGN - 1) & ~(_ALIGN - 1)); 
        }

        /*  根據(jù)區(qū)塊大小使用第n號(hào)free_list  */
        static size_t FREELIST_INDEX(size_t bytes) 
        {  
            return (((bytes) + _ALIGN - 1) / _ALIGN - 1);  
        }
        
        /*  為free_list某個(gè)大小的list增加節(jié)點(diǎn)  */
        static void *refill(size_t n);

        static char *chunk_alloc(size_t size, int &nobjs);
    public:
        static void *allocate(size_t n);
        static void deallocate(void *p, size_t n);
        static void *reallocate(void *p, size_t old_size, size_t new_size);
};
  • 空間配置函數(shù)
void* alloc::allocate(size_t n) 
{  
    obj **my_free_list, *list;
    if (n > (size_t) _MAX_BYTES)    // 當(dāng)需要的內(nèi)存大于某個(gè)節(jié)點(diǎn)仑嗅,就調(diào)用malloc
        return malloc(n);

    my_free_list = free_list + FREELIST_INDEX(n);    // 指向第n號(hào)list
    list = *my_free_list;
    
    if (list) {
        *my_free_list = list->free_list_link;    // 從list頭部"拔出一個(gè)內(nèi)存",返回給客戶
        return list;
    } else        
        return refill(ROUND_UP(n));    // 如果當(dāng)前l(fā)ist為空张症,則重新申請(qǐng)內(nèi)存填充該list
}
  • 空間釋放函數(shù)
void alloc::deallocate(void *p, size_t n) 
{
    obj *q = (obj *) p;
    obj **my_free_list;
    
    if (n > (size_t)_MAX_BYTES)    // 當(dāng)需要的內(nèi)存大于某個(gè)節(jié)點(diǎn)仓技,就調(diào)用free
        free(p);
    else {            // 當(dāng)需要的內(nèi)存小于某個(gè)節(jié)點(diǎn),就將其保存至某個(gè)list下
        my_free_list = free_list + FREELIST_INDEX(n);    // my_free_list指向第n號(hào)list
        q->free_list_link = *my_free_list;  
        *my_free_list = q;
    }
}
  • 從內(nèi)存池取出內(nèi)存供給free list使用
chunk_alloc.png
// 從內(nèi)存池取出空間給free_list使用(第n號(hào))(假定size已經(jīng)適當(dāng)調(diào)整為8的倍數(shù))
char *alloc::chunk_alloc(size_t size, int &n_objs) 
{    
    char *result;
    size_t total_bytes = size * n_objs;              // 需要的內(nèi)存總量
    size_t bytes_left = end_free - start_free;       // 內(nèi)存池剩余空間

    if (bytes_left >= total_bytes) {
        // 內(nèi)存池剩余空間空間完全滿足需要
        result = start_free;
        /* 更新start_free指針 */
        start_free += total_bytes;

        return result;
    } else if (bytes_left >= size) {
        // 內(nèi)存池剩余空間不能完全滿足需求量,但足夠供應(yīng)一個(gè)(含)以上的區(qū)塊
        n_objs = bytes_left / size;    // 計(jì)算可以供應(yīng)幾個(gè)區(qū)塊
        /* 更新start_free指針 */
        total_bytes = n_objs * size;
        result = start_free;
        start_free += total_bytes;

        return result;
    } else {
        // 內(nèi)存池剩余空間連一個(gè)區(qū)塊的大小都不滿足
        size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
        // 試著讓內(nèi)存池中殘余零頭還有利用價(jià)值
        if ( bytes_left > 0 ) {
            // 將內(nèi)存池殘余內(nèi)存配給適當(dāng)?shù)膄ree_list(更小的size的list);
            obj **my_free_list = free_list + FREELIST_INDEX(bytes_left);
            ((obj *) start_free)->free_list_link = *my_free_list;
            *my_free_list = (obj *) start_free;
        }
        // 配置heap空間, 用來補(bǔ)充內(nèi)存池
        start_free = (char *) malloc(bytes_to_get);
        if (nullptr == start_free) {
            obj *p, **my_free_list;
            // heap空間不足,搜尋適當(dāng)?shù)膄ree_list("未用區(qū)塊,且區(qū)塊夠大")
            for (int i = size; i <= _MAX_BYTES; i += _ALIGN) {
                my_free_list = free_list + FREELIST_INDEX(i);
                p = *my_free_list;
                if (0 != p) {
                    *my_free_list = p->free_list_link;
                     start_free = (char *)p;
                     end_free = start_free + i;
                     return chunk_alloc(size, n_objs);
                }
           }
           end_free = 0;
        }
        heap_size += bytes_to_get;
        end_free = start_free + bytes_to_get;
        
        return chunk_alloc(size, n_objs);
   }
}

參考資料
[1] 《STL源碼剖析》侯捷

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俗他,一起剝皮案震驚了整個(gè)濱河市脖捻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌兆衅,老刑警劉巖地沮,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異羡亩,居然都是意外死亡摩疑,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門畏铆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雷袋,“玉大人,你說我怎么就攤上這事辞居∑牛” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵速侈,是天一觀的道長率寡。 經(jīng)常有香客問我,道長倚搬,這世上最難降的妖魔是什么冶共? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上捅僵,老公的妹妹穿的比我還像新娘家卖。我一直安慰自己,他們只是感情好庙楚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布上荡。 她就那樣靜靜地躺著,像睡著了一般馒闷。 火紅的嫁衣襯著肌膚如雪酪捡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天纳账,我揣著相機(jī)與錄音逛薇,去河邊找鬼。 笑死疏虫,一個(gè)胖子當(dāng)著我的面吹牛永罚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播卧秘,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼折砸,長吁一口氣:“原來是場噩夢啊……” “哼章办!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤竖螃,失蹤者是張志新(化名)和其女友劉穎搏讶,沒想到半個(gè)月后改艇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兰粉,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年恋昼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了看靠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡液肌,死狀恐怖挟炬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嗦哆,我是刑警寧澤谤祖,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站老速,受9級(jí)特大地震影響粥喜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜橘券,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一额湘、第九天 我趴在偏房一處隱蔽的房頂上張望卿吐。 院中可真熱鬧,春花似錦锋华、人聲如沸嗡官。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽衍腥。三九已至,卻和暖如春纳猫,著一層夾襖步出監(jiān)牢的瞬間婆咸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工续担, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留擅耽,地道東北人活孩。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓物遇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親憾儒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子询兴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容