专栏名称: 苏小林
目录
相关文章推荐
51好读  ›  专栏  ›  苏小林

memcached内存分配策略源码分析

苏小林  · 掘金  ·  · 2019-08-23 15:53

正文

阅读 44

memcached内存分配策略源码分析

本文基于memcached 1.2.0写成

memcached的内存分配器slab.c不过300行代码,还是比较容易上手分析的。

内存模型如下:

一个slabclass_t管理了多个slab,每个slab被称为内存页,每个slab管理多个item的内存空间

核心函数

函数名 作用
slabs_init 初始化slabclass_t结构体数组
slabs_clsid 通过内存大小从slabclass_t数组中找到最小能满足的结构体
slabs_preallocate 给每个slabclass_t先分配一个slab(页)的内存(1mb)
slabs_newslab 给指定的slabclass分配一个新的slab存放到slab_list上,同时slabs、end_page_ptr、end_page_free发生相应变化
grow_slab_list 动态增加slab_list数组的大小
slabs_alloc 从内存分配器中取出一个空的item内存来使用
slabs_free 将item所在的内存指针重新标记成可使用,相当于删除了item
slabs_stats 从slabclass_t结构体上获取内存分配器的使用情况

其中被slab.c以外的文件调用的函数有slabs_alloc、slabs_free、slabs_init和slabs_stats

slabs_init内部调用关系

slabs_alloc内部调用关系

内存分配生命周期

初始化机制-slabs_init()函数

  1. 计算每个item的初始占用的内存大小
unsigned int size = sizeof(item) + settings.chunk_size;
复制代码
  1. 根据size值和每个内存页1mb大小算出当前slabclass_t的每个slab能够存放多少个item放到perslab属性上
  2. 按照factor这个缩放值增大size(size=size*factor)继续初始化下一个slabclass_t

获取item的内存机制-slabs_alloc()函数

这里有一个分支,如果当前slabclass的当前slab还有剩余的内存空间,直接就分配了,参考:

if (! (p->end_page_ptr || p->sl_curr || slabs_newslab(id)))
    return 0;
复制代码

三种情况

  1. 当前页还有内存空间 p->end_page_ptr
  2. 有item被删除了释放的空间p->sl_curr
  3. 给当前的slabclass_t分配一个新页 slabs_newslab(id)
/* return off our freelist, if we have one */
if (p->sl_curr)
    return p->slots[--p->sl_curr];

/* if we recently allocated a whole page, return from that */
if (p->end_page_ptr) {
    void *ptr = p->end_page_ptr;
    if (--p->end_page_free) {
        p->end_page_ptr += p->size;
    } else {
        p->end_page_ptr = 0;
    }
    return ptr;
}
复制代码

删除item的内存释放机制

主要就是把删除的item放进slabclass_t的slots数组中,申请内存时,优先从这个slots中获取,达到这个memcached解决内存碎片的目的

这里有个对这个存放被删除的item的slots数组扩容的操作

if (p->sl_curr == p->sl_total) { /* need more space on the free list */
                            

                            





请到「今天看啥」查看全文