博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

memcached源码阅读笔记二

Posted on 2013-09-25 16:37  david2303  阅读(266)  评论(0编辑  收藏  举报

这一次是关于内存使用的分析

 

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;
}