Memcached 内存分配与SLAB 机制


Memcached 内存分配与 SLAB 机制 Home, Beijing Langwan http://www.echohello.cn/ December 2010 目录 第 1 章 前言..................................................................................................................................... 2 第 2 章 slab 机制 ............................................................................................................................. 2 第 3 章 启动参数 ............................................................................................................................. 2 3.1 -m ........................................................................................................................................ 3 3.2 –M ....................................................................................................................................... 3 3.3 –f ......................................................................................................................................... 3 3.4 –n ........................................................................................................................................ 3 3.5 –L ......................................................................................................................................... 3 3.6 –I.......................................................................................................................................... 3 第 4 章 详细逻辑 ............................................................................................................................. 3 4.1 初始化 slab class................................................................................................................ 3 4.2 申请资源............................................................................................................................ 4 4.2.1 确认 class id ............................................................................................................ 4 4.2.2 申请 chunk .............................................................................................................. 5 4.2.3 线程安全 ................................................................................................................. 5 4.2.4 LRU ........................................................................................................................... 5 4.3 释放资源............................................................................................................................ 6 第 5 章 内存分配的其它问题 ......................................................................................................... 6 5.1 LRU 策略 ............................................................................................................................. 6 第1章 前言 文章比较短,但主要的内存分配问题已经分析的很清楚了,需要更详细了解,请顺着文 章阅读一下源代码即可。 第2章 slab 机制 slab 是 Memcached 用来存放 item 的一种机制,如下图所示: slab class 可以被看做一个没有底的桶,后面我们简称为 class,class 本身没有大小的概 念,只有页数,每页默认不超过 1M,因此一个 class 就是一个多页集合,每页里存放着 chunk, 不同 class 的页大小是一致的,但 chunk 的大小是不一致的,默认情况下 class 1 的 chunk 大 小是 96 字节,class 42 的 chunk 大小是 1M,因此不同 class 里的 page 能容纳的 chunk 单元 数不同,class 1 每页可以放 1 万个单元,class 每页只能放 1 个单元,所有 class 所分配的内 存总数不能超过默认 64M,也就是启动项中的-m 参数,当已经没有更多的内存可以分配的 时候,memcached 开始进行 LRU 处理,淘汰已经过期的内容。 不同 class 之间的 chunk 大小是依据 factor 来计算的,默认值是 1.25,也就是下一个 class 的 chunk 大小是上个 class 的 1.25 倍。 第3章 启动参数 mamcached 中有一些与内存分配有关的参数,我们进行一下介绍。 3.1 -m 可使用内存的总大小,当达到这个值的时候,memcached 开始启用 LRU 淘汰内容,默 认是 64m,这是一般系统都需要设置的值。 3.2 –M 禁用 LRU 机制,当内存耗尽的时候不淘汰旧内容。 3.3 –f 增长因子默认值 1.25,增长因子越小 class 分配的越多,增长因子设置的越大 class 越少。 3.4 –n 可以被看做是 chunk 的最小值,默认值是 48 字节,但由于 chunk 本身的数据结构也是 48 字节,所以最小 chunk 大小就变成了 96 字节,总是比你想分配的要大 48 字节。 3.5 –L 尝试一次性申请-m 中规定的最大内存,所有未来的内存开销都基于这块内存,而不在 向系统中进行分配。 3.6 –I 每个 slab page 的大小,默认是 1M,最大可以设置为 128M,因此 chunk 的大小是在-n 与-I 参数之间依据-f 参数进行增长。 第4章 详细逻辑 4.1 初始化 slab class slabs_init(settings.maxbytes, settings.factor, preallocate); maxbytes 等价于 –m 指定的内存分配最大值,factor 等价于-f 参数, preallocate 等价 于-L 参数,下面为初始化过程的描述 如果设置了-L 参数尝试一次性申请 maxbytes 大小的内存,指针保存到全局的 mem_base 变量里,未来所有内存申请实际上是从这块内存区域中调配的。 初始化 slabclass,用于维护所有 slab class 信息,默认情况下一次性初始化为 200 个, 并且 class 的最大数量也是 200 个。 计算每个 class 中的 chunk 尺寸,计算每个 page 可以容纳的 chunk 数量,也就是 perslab (每页可容纳的 chunk 数量),如果-I 指定的大小为 1M,chunk 的尺寸为 500K,那么 perslab 的值是 2,如果 chunk 的尺寸是 600K 或 700K,那么 perslab 的值只能是 1。 在初始化的过程当中,并没有为每个 class 预分配任何内容,只是预算了不同 class 的结 构信息,除非你去掉了源代码中的 DONT_PREALLOC_SLABS 宏定义,这时候在初始化的时候 就会为每个 class 先分配 16 页的空间,代码如下: 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; 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; } 当第一次分配的时候一次性分配 16 页,未来每次满了按照原有规模的 2 倍进行扩张。 4.2 申请资源 4.2.1 确认 class id 前端每次提交不同大小的数据,因此首先要确认这些数据需要归属到那个桶里进行存放, 轮询每个桶的 chunk,返回 class 的 id unsigned int slabs_clsid(const size_t size) { int res = POWER_SMALLEST; if (size == 0) return 0; while (size > slabclass[res].size) if (res++ == power_largest) /* won't fit in the biggest slab */ return 0; return res; } 4.2.2 申请 chunk 申请过程涉及到两个函数,一个函数用于从 class 里分配空闲的 chunk,一个函数用于 申请新的 slab page。 static void *do_slabs_alloc(const size_t size, unsigned int id); static int do_slabs_newslab(const unsigned int id); 当无法从 do_slabs_newslab()中分配出新的空间,导致 do_slabs_alloc()也只能返回 NULL 的时候,memcached 进行 LRU 淘汰。 4.2.3 线程安全 Memcached 里的函数由于线程安全的问题,所以都是两个样子 do_slabs_alloc()对应 slabs_alloc()函数,区别在于后者是线程安全的。 4.2.4 LRU if (it == NULL && (it = slabs_alloc(ntotal, id)) == NULL) { /* ** Could not find an expired item at the tail, and memory allocation ** failed. Try to evict some items! */ tries = 50; /* If requested to not push old items out of cache when memory runs out, * we're out of luck at this point... */ if (settings.evict_to_free == 0) { itemstats[id].outofmemory++; return NULL; } /* * try to get one off the right LRU * don't necessariuly unlink the tail because it may be locked: refcount>0 * search up from tail an item with refcount==0 and unlink it; give up after 50 * tries */ 这是 do_item_alloc()函数中的一段,当无法从现有 chunk 中找到过期内容同时无法从 class 里继续分配新的 chunk,这时候尝试 LRU 过程,先删过期内容,如果还无法分配,就开 始删最近的内容。 4.3 释放资源 无论是通过 LRU 策略还是通过其它主动淘汰策略,都需要标记 refcount = 0(引用计数), 然后才会通过 do_slabs_free()释放资源,等待其它资源申请的时候使用。 第5章 内存分配的其它问题 5.1 LRU 策略 分三次淘汰内容,当为新的内容申请资源的时候,第一次先尝试 50 次寻找已经过期的 单元,如果找到过期内容,就把过期内容送给新内容。 如果没有找到过期内容,又无法从 slab class 中分配资源,就再尝试 50 次从最近没有使 用的内容中剔除内容,把空出来的资源给新内容。 如果还无法从 slab class 中分配资源,就从 3 个小时以前的内容中直接清理 50 笔数据, 把空出来的资源交给新内容。
还剩5页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

wayne1984

贡献于2012-03-30

下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf