2012年10月29日星期一

memcached中的内存管理

memcached,分布式K-V内存缓存服务,其核心为内存管理,下面我们就来了解memcached管理内存的方式、解读这部分代码,本文基于memcached 1.4.15版本。

memcached以类似Linux内核中的slab内存分配机制进行内存管理:













一块连续的1M大小的page被分成多个等大的chunk,slab class管理特定大小的chunk。一对K-V组成一个item,一个item被放置到一块chunk中。

除了以上结构外,memcached使用名为slots的链表,管理空闲的chunk:

memcached对内存的管理主要是对slabclass和slots链表的维护。slabclass_t结构如下:

下面从memcached初始化内存管理结构、add/delete操作分析相应的memcached代码。

初始化内存管理结构

main函数中,调用slabs_init进行内存管理相关的初始化工作。slabs_init函数中,初始化数组长度为MAX_NUMBER_OF_SLAB_CLASSES的slabclass数组,对每个slab class,填入size和per slab值。size值为sizeof(item) + settings.chunk_size,即最小为96,默认factor为1.25,size若不足8的倍数则补齐。

初始化过程很简单,初始化完成后memcached也并没有真正从操作系统获取物理内存。

add操作

拉起memcached服务后,memcached即对端口进行监听,等待请求的到来。在memcached客户端执行add操作后,函数调用过程如下:

event_handler -> drive_machine -> try_read_command -> process_command -> process_update_command -> item_alloc -> do_item_alloc -> slabs_alloc ->  do_slabs_alloc

在do_item_alloc函数中,调用slabs_clsid函数,slabs_clsid根据添加的key的长度计算所要放置到的slabclass的下标,计算方法为遍历slabclass数组,将key长度与slabclass->size进行比较。

在do_slabs_alloc函数中,首先判断是否有空闲的chunk,即sl_curr值是否为零。如果sl_curr非零,则从slots中取chunk;否则调用do_slabs_newslab完成page申请。
do_slabs_newslab -> split_slab_page_into_freelist -> do_slabs_free

do_slabs_newslab调用memory_allocate从系统申请1M大小的内存,之后调用split_slab_page_into_freelist将1M内存分成等大的chunk,split_slab_page_into_freelist 对每块chunk调用do_slabs_free,将这些新生成的空闲chunk加入slots链表。完成以上动作,do_slabs_newslab函数中,将新申请的page加入slab_list数组。

完成空闲chunk申请后,在do_item_alloc函数中,将key、key长度、value等值填到chunk中:
delete操作

对应delete操作,函数调用过程如下:
event_handler -> drive_machine -> try_read_command -> process_command -> process_delete_command -> item_get -> do_item_get -> item_remove -> do_item_remove -> item_free -> slabs_free -> do_slabs_free

在do_slabs_free中,内存并不是真正归还系统,而是放到相应slab class的slots链表头部:

Have fun!



没有评论:

发表评论