memcached源碼閱讀筆記二

這一次是關於內存使用的分析數組

 

int main (int argc, char **argv) {
    //.......................
    //.......................
    //.......................
    slabs_init(settings.maxbytes, settings.factor, preallocate);
    
    //.......................
    //.......................
    //.......................
    
}


void slabs_init(const size_t limit, const double factor, const bool prealloc) {
    int i = POWER_SMALLEST - 1;
    unsigned int size = sizeof(item) + settings.chunk_size;
    
    mem_limit = limit;
    
    // 一個記錄slab數據的結構體
    memset(slabclass, 0, sizeof(slabclass));
    
    while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {
        /* Make sure items are always n-byte aligned */
        // 取整
        if (size % CHUNK_ALIGN_BYTES)
            size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);
        
        // 一個slab大小爲1MB
        // 定出一個item的大小
        slabclass[i].size = size;
        // 定出每個slab有多少個item數量
        slabclass[i].perslab = settings.item_size_max / slabclass[i].size;
        // 下一種slab的item大小爲當前的的factor倍,通常爲1.25
        size *= factor;
    }
    
    // 最後一種slab。每個item爲item_size_max,通常爲1MB,每一個slab只有一個item
    power_largest = i;
    slabclass[power_largest].size = settings.item_size_max;
    slabclass[power_largest].perslab = 1;

}



// 分配一個新的slab出來
static int do_slabs_newslab(const unsigned int id) {
    slabclass_t *p = &slabclass[id];
    int len = settings.slab_reassign ? settings.item_size_max
    : p->size * p->perslab;
    char *ptr;
    
    if (
        (mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) ||
        // 若是沒有超出mem_limit
        
        (grow_slab_list(id) == 0) ||
        // 判斷這種slab,是否須要變大list_size
        // 而且grow_slab_list返回1
        
        ((ptr = memory_allocate((size_t)len)) == 0)
        //
        // 則調用memory_allocate分配一個slab的內存
        
        ) {
        
        return 0;
    }
    
    memset(ptr, 0, (size_t)len);
    split_slab_page_into_freelist(ptr, id);
    // 將新分配的內存放到slots中,也就是空閒列表中
    
    // add this new slab in the array of slab list
    p->slab_list[p->slabs++] = ptr;
    mem_malloced += len;
    
    return 1;
}

// slab的數組增加
static int grow_slab_list (const unsigned int id) {
    slabclass_t *p = &slabclass[id];
    if (p->slabs == p->list_size) {
        size_t new_size =  (p->list_size != 0) ? p->list_size * 2 : 16;
        // 初始大小16,而後之後不夠用了,增大一倍
        void *new_list = realloc(p->slab_list, new_size * sizeof(void *));
        if (new_list == 0) return 0;
        p->list_size = new_size;
        p->slab_list = new_list;
    }
    return 1;
}



// 我須要一個item,分一個給我吧
static void *do_slabs_alloc(const size_t size, unsigned int id) {
    slabclass_t *p;
    void *ret = NULL;
    item *it = NULL;
    
    
    p = &slabclass[id];
    assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0);
    //要麼sl_curr空閒列表爲空,不爲空時slots指向的頭一個item的cslid值必須爲0
    
    //若是空閒列表不爲空,直接從空閒列表中分配
    //若是空閒列表爲空,則do_slabs_newslab來增長該slabclass的slabs
    if (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) {
        /* We don't have more memory available */
        ret = NULL;
    } else if (p->sl_curr != 0) {
        /* return off our freelist */
        it = (item *)p->slots;
        p->slots = it->next;
        if (it->next) it->next->prev = 0;
        p->sl_curr--;
        ret = (void *)it;
    }
    
    if (ret) {
        p->requested += size;
        MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret);
    } else {
        MEMCACHED_SLABS_ALLOCATE_FAILED(size, id);
    }
    
    return ret;
}



// free並非將內存返回給系統,而是將不使用的item佔用的空間從新放到相對應的slabclass的slots中
static void do_slabs_free(void *ptr, const size_t size, unsigned int id) {
    slabclass_t *p;
    item *it;
    
    p = &slabclass[id];
    
    it = (item *)ptr;
    it->it_flags |= ITEM_SLABBED;
    it->prev = 0;
    it->next = p->slots;
    if (it->next) it->next->prev = it;
    p->slots = it;
    // 把這個item放到slot中。上面是一連串雙向鏈表的操做
    
    p->sl_curr++;
    p->requested -= size;
    return;
}
相關文章
相關標籤/搜索