memcached源代码分析
- 格式:ppt
- 大小:702.00 KB
- 文档页数:31
pythonmemcache简单操作python memcache 简单操作 (用于web前端优化,减少读库次数)2013-05-21 09:29:11| 分类: Python | 标签: |举报 |字号大中小订阅Memcached官网简单介绍:memcached很强大,它可以支持分布式的共享内存缓存,大型站点都用它。
对小站点来说,有足够内存的话,使用它也可以得到超赞的效果。
使用目的:由前面的介绍看到,大家使用它都是为了速度,不过我却是为了解决Session在不同浏览器中偶尔丢失的数据。
其实也不能怪浏览器啦,主要是我需要一个dict类型的session,哈哈。
安装Linux安装包对于大多数Linux发行版本来说,可以使用官方推荐的方法:Debian/Ubuntuapt-get install memcachedRedhat/Fedora/CentOSyum install memcached源码安装(CentOS 5.5)1、下载libevent(依赖)和memcached分别到以下引用地址下载最新版本:引用地址/~provos/libevent/引用地址:/p/memcached/downloads/list2、安装ibevent(依赖)和memcachedlibevent(目前最新是libevent-2.0.10-stable.tar.gz,请注意版本号)tar xvf libevent-2.0.10-stable.tar.gzcd libevent-2.0.10-stable./configure --prefix=/usr/local/libevent/makemake install接着,ls /usr/local/libevent/lib,将查看到的第一个类似libevent-X.X.so.Xln -s /usr/local/libevent/lib/libevent-2.0.so.5 /lib/libevent-2.0.so.5memcached (目前最新是1.4.5,请注意版本号)tar zxvf memcached-1.4.5.tar.gzcd memcached-1.4.5./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent/makemake install3、启动memcached启动参数说明(这是我是复制粘贴的,如有错误请指正):-d 选项是启动一个守护进程-m 是分配给Memcache使用的内存数量,单位是MB,默认64MB-M return error on memory exhausted (rather than removing items)-u 是运行Memcache的用户,如果当前为root 的话,需要使用此参数指定用户-l 是监听的服务器IP地址,默认为所有网卡-p 是设置Memcache的TCP监听的端口,最好是1024以上的端口-c 选项是最大运行的并发连接数,默认是1024-P 是设置保存Memcache的pid文件-f chunk size growth factor (default: 1.25)-I Override the size of each slab page. Adjusts max item size(1.4.2版本新增)例子:/usr/local/memcached/bin/memcached -d -m 100 -c 1000 -u root -p 11211可以启动多个守护进程,但是端口不能重复。
memcached编译
要编译Memcached,首先你需要确保你的系统中安装了编译Memcached所需的依赖项。
通常情况下,你需要安装开发工具包和
相关的库文件。
接下来,你可以按照以下步骤进行编译:
1. 下载Memcached源代码,你可以从Memcached官方网站或者GitHub上获取Memcached的源代码。
下载后解压到你选择的目录中。
2. 进入解压后的Memcached目录,使用终端或命令行工具进入
解压后的Memcached目录。
3. 运行配置脚本,运行`./configure`命令来配置Memcached
的编译选项。
你可以使用`--help`参数来查看可用的配置选项。
例如,你可以指定安装路径等选项。
4. 编译,运行`make`命令来编译Memcached。
这将会生成可执
行文件。
5. 安装,运行`make install`命令来安装编译好的Memcached
可执行文件和相关的文件到系统中。
你可能需要使用`sudo`命令来
获取足够的权限进行安装。
完成上述步骤后,你就成功地编译并安装了Memcached。
你可以通过运行`memcached`命令来启动Memcached服务器。
记得查看Memcached的文档以获取更多详细的信息和配置选项。
希望这些步骤可以帮助你成功编译Memcached。
Memcached源码剖析笔记XguruMemcached是一个自由、源码开放、高性能、分布式内存对象缓存系统,目的在于通过减轻数据库负载来使动态Web应用程序提速。
目录1.背景 (3)2.memcached的安装 (4)3.memcached的配置 (5)4.memcached的使用 (6)4.1.存储命令 (7)4.2.读取命令 (8)4.3.删除命令 (8)4.4.高级命令 (9)4.5.其他命令 (10)5.Memcached内部工作机制 (11)5.1.Memcached基本的数据结构 (11)5.2.基本设计概念和处理流程 (12)5.3.内部Hash机制 (15)5.3.1.Hash函数及冲突解决 (15)5.3.2.HashTable主要函数 (15)5.4.slab内存处理机制 (17)5.4.1.slab主要函数 (17)5.4.2.slab机制中所采用的LRU算法 (19)5.5.控制item各种函数 (20)5.6.守护进程机制 (22)5.7.Socket处理机制 (23)15.7.1.Unix域协议 (23)5.7.2.TCP/UDP协议 (24)5.8.多线程处理机制 (25)5.9.事件处理机制 (25)6.未完善之处 (27)7.参考文献 (28)21.背景Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。
它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。
Memcached基于一个存储键/值对的hashmap。
Memcached是一个自由、源码开放、高性能、分布式内存对象缓存系统,目的在于通过减轻数据库负载来使动态Web应用程序提速。
Memcached是一个在内存中对任意的数据(比如字符串,对象等)所使用的key-value 存储。
数据可以来自数据库调用,API调用,或者页面渲染的结果。
memcached源码分析⼀-slabSlab作为⼀种内存管理⽅案,其作⽤主要有以下2点:a) 避免频繁的内存分配释放造成的内存碎⽚b) 减少内存分配操作产⽣的性能开销Linux内核数据结构中也有slab的设计,Linux提供了⼀套接⼝,使⽤这套接⼝可以动态创建与释放⼀个slab结构,该slab的chunk⼤⼩通过接⼝指定,创建成功后就可以从该slab中动态申请与释放chunk⼤⼩的内存⽤于存储⽬标数据,例如内核中⽤于表⽰进程的结构体task_struc 就是使⽤的slab⽅式进⾏管理。
memcached与linux内核不同,memcached中在程序启动时即初始化⼀个slabclass_t的全局数组,每⼀个slabclass_t结构的chunk⼤⼩不同,构成⼀个全局slab池。
memcached中的slab相关操作源码主要集中在源⽂件slabs.c中,下⾯对它进⾏分析。
1. 结构体slabclass_t以下是memcached中对slabclass_t的定义,typedef struct {unsigned int size; /* sizes of items */unsigned int perslab; /* how many items per slab */void *slots; /* list of item ptrs */unsigned int sl_curr; /* total free items in list */unsigned int slabs; /* how many slabs were allocated for this class */void **slab_list; /* array of slab pointers */unsigned int list_size; /* size of prev array */size_t requested; /* The number of requested bytes */} slabclass_t;slabclass_t对内存的组织可以粗略的⽤图1-1表⽰,图1-1 slabclass_t内存组织⽅式slab_list是⼀个可以动态分配的数组,数组⼤⼩以list_size表⽰,数组中已存储元素数⽬以slabs表⽰,数组中每⼀个元素都表⽰⼀个page ⼤⼩的可⽤内存(page也称为slab)。
Python中的Memcached缓存Memcached是一款高性能的分布式内存对象缓存系统。
它的主要功能是将数据存储在内存中,从而提高数据访问速度。
作为一款大型网站所必不可少的缓存工具,Memcached在Python 中的应用极度广泛。
在这篇论文中,我们将深入探讨Memcached在Python中的应用,分析其优点和缺点,并提出一些最佳实践,以帮助开发人员更好地利用Memcached提升应用的性能和用户体验。
一、Memcached的优点1.高速缓存Memcached是一款基于内存的缓存系统,它可以实现非常快速的缓存访问速度。
由于数据存储在内存中,所以它的响应速度相当快,甚至可以达到微秒级别。
在大型网站前端中,常使用Memcached来缓存一些静态或不怎么变化的数据,如网站配置信息、静态页面等。
通过缓存这些数据,可以减少对数据库等后端系统的请求,从而提高网站的性能。
2.可扩展性Memcached是一款分布式缓存系统,它可以将缓存数据分散存储在多台机器的内存中,从而实现更大的存储容量和更高的并发处理能力。
在高并发的情况下,系统可以简单地通过增加或减少服务器数量来扩展缓存能力。
此外,Memcached还具有自动数据平衡和故障转移等功能,可以实现高可用性和灵活性。
3.支持多种语言Memcached支持多种语言,包括Python、Java、PHP等,可以方便地嵌入到各种应用程序中,快速提高应用程序的性能。
在Python中,Memcached是一种常见的缓存解决方案,可以通过安装对应的Python模块,轻松地集成到应用程序中。
二、Memcached的缺点1.容量限制由于Memcached是一款基于内存的缓存系统,所以它的缓存容量是有限的。
在实际应用中,需要根据业务需求和服务器硬件条件等因素综合考虑,设置合适的缓存容量,避免因容量不足而导致缓存失效。
2.数据不持久化Memcached只是一款内存缓存系统,它并不支持数据持久化。
memcached字符编码Memcached 是一款开源的高性能分布式内存对象缓存系统,它主要用于缓存数据库查询结果、API调用结果或其他计算成本高的操作的结果,从而提高应用程序的性能和响应速度。
在 Memcached 中,字符编码主要涉及两个方面,存储数据时的编码和读取数据时的解码。
1. 存储数据时的编码:当我们向 Memcached 存储数据时,通常是以字符串的形式进行存储。
Memcached 默认使用的字符编码是 ASCII 编码,它是一种基于拉丁字母的字符编码标准,支持英文字母、数字和一些特殊字符。
ASCII 编码每个字符占用一个字节的存储空间。
另外,Memcached 也支持使用其他字符编码存储数据,如UTF-8 编码。
UTF-8 是一种可变长度的 Unicode 字符编码,它可以表示世界上几乎所有的字符。
UTF-8 编码中,英文字母和数字仍然只占用一个字节的存储空间,而中文、日文、韩文等非拉丁字符则占用多个字节的存储空间。
2. 读取数据时的解码:当我们从 Memcached 中读取数据时,Memcached 会将存储的字符串数据解码成对应的字符编码。
如果存储时使用的是 ASCII编码,那么读取时就会解码成 ASCII 编码的字符串。
同理,如果存储时使用的是 UTF-8 编码,那么读取时就会解码成 UTF-8 编码的字符串。
在读取数据时,我们的应用程序需要根据具体的需求和使用的编程语言,将解码后的字符串再进行进一步的处理和转换。
例如,在使用 Python 进行开发时,可以使用内置的字符串处理函数来处理解码后的字符串。
需要注意的是,Memcached 本身并不关心存储的数据的具体编码方式,它只是将数据当作二进制的字节流进行存储和读取。
因此,在使用 Memcached 存储和读取数据时,我们需要确保应用程序和Memcached 之间的数据编码方式是一致的,以避免出现乱码或数据解析错误的情况。
memcache slab模块源码解读slab模块简介由于采用常用的malloc和free函数会造成内存碎片比较多,所以memcache采用的是自己写的slab内存管理模块来管理内存,特点如下:∙系统中用不同大小的chunk(struct item)来存数据,对某个需要缓存的数据,找到最适合大小的item来保存∙系统中分为多个slabclass,每个slabclass有一个或多个slab,每个slab 里面包含多个大小相同的itemslab结构体关系图我们从某个slabclass来看其与slab、item之间的关系从图中可以看出,每个slabclass对应一个或多个slab,在slabclass_t结构体里面有个slab_list数组,其指向的是每个slab内存块的首地址(在这里,特别说明一下,slab是一段连续的内存空间,和操作系统中的内存页有点类似,memcache没有专门的一个结构体来描述它,只要其首地址来比较某个slab),而每个slab中有多个chunk(struct item)数据块用来存数据整个系统的slab初始化过程在memcache模块初始化的时候,首先调用的函数是slab_init,其源码如下:/*** Determines the chunk sizes and initializes the slab class descriptors* accordingly.*/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;if (prealloc) {/* Allocate everything in a big chunk with malloc */mem_base = malloc(mem_limit);if (mem_base != NULL) {mem_current = mem_base;mem_avail = mem_limit;} else {fprintf(stderr, "Warning: Failed to allocate requested memory in" " one large chunk.\nWill allocate in smaller chunks\n"); }}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);slabclass[i].size = size;slabclass[i].perslab = settings.item_size_max / slabclass[i].size;size *= factor;if (settings.verbose > 1) {fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n", i, slabclass[i].size, slabclass[i].perslab);}}power_largest = i;slabclass[power_largest].size = settings.item_size_max;slabclass[power_largest].perslab = 1;if (settings.verbose > 1) {fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",i, slabclass[i].size, slabclass[i].perslab);}/* for the test suite: faking of how much we've already malloc'd */{char *t_initial_malloc = getenv("T_MEMD_INITIAL_MALLOC");if (t_initial_malloc) {mem_malloced = (size_t)atol(t_initial_malloc);}}if (prealloc) {slabs_preallocate(power_largest);}}我们来分析这个函数:1.首先申请mem_limit大小的内存块2.while循环中对管理item大小不同的slabclass_t结构体进行初始化3.调用slabs_preallocate对分配mem_limit大小的内存块进行具体的处理下面,我们来看slabs_preallocate的代码:static void slabs_preallocate (const unsigned int maxslabs) {int i;unsigned int prealloc = 0;/* pre-allocate a 1MB slab in every size class so people don't getconfused by non-intuitive "SERVER_ERROR out of memory"messages. this is the most common question on the mailinglist. if you really don't want this, you can rebuild withoutthese three lines. */for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) {if (++prealloc > maxslabs)return;if (do_slabs_newslab(i) == 0) {fprintf(stderr, "Error while preallocating slab memory!\n""If using -L or other prealloc options, max memory must be " "at least %d megabytes.\n", power_largest);exit(1);}}}从代码可以看出:1.slabs_preallocate会对所有的slabclass_t进行分配slab的操作(这里需要注意的是,初始化的时候默认每个slabclass是只有一个slab的),即do_slabs_newslab函数下面就进接着看do_slabs_newslab函数static int do_slabs_newslab(const unsigned int id) {slabclass_t *p = &slabclass[id];int len =? settings.item_size_max: p->size * p->perslab;char *ptr;if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) ||(grow_slab_list(id) == 0) ||((ptr = memory_allocate((size_t)len)) == 0)) {MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id);return 0;}memset(ptr, 0, (size_t)len);split_slab_page_into_freelist(ptr, id);p->slab_list[p->slabs++] = ptr;mem_malloced += len;MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id);return 1;}do_slabs_newslab函数的功能就是为某个slabclass新分配一个slab大小的内存块1.当memcache分配一个新的slab时会造成所使用的内存超过对定的mem_limit大小时,则会提示内存不够分配2.当mem_limit大小的内存够分配的时候,则调用grow_slab_list来根据需要扩充struct slabclass_t中void **slab_list数组的大小,然后就是用memory_allocate函数分配一个slab内存块3.然后调用split_slab_page_into_freelist函数把slab内存块分成若干个item,然后把这些空闲的item都插入到slabclass_t中的void *slots指向的链表中4.把新分配的slab的首地址添加到'slabclass_t`数组中去5.跟新memcache已申请的内存大小mem_malloced这样memcache的slab模块的初始化工作就完成了item相关操作在整个memcache内存管理slab系统初始化完成后,就进入了memcahe的运行阶段,这时候,会涉及到的一些操作是(在文件items.c中)∙item的分配∙item的释放∙item获取∙item链接到队列(当一个item被set的时候,会链接到队列)∙item从队列中取消链接下面我们会依次序来说上述的几个操作:item的分配item的分配对应于do_item_alloc先给出do_item_alloc的程序流程图然后贴出代码item *do_item_alloc(char *key, const size_t nkey, const int flags,const rel_time_t exptime, const int nbytes,const uint32_t cur_hv) {uint8_t nsuffix;item *it = NULL;char suffix[40];size_t ntotal = item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix); if (e_cas) {ntotal += sizeof(uint64_t);}unsigned int id = slabs_clsid(ntotal);if (id == 0)return 0;mutex_lock(&cache_lock);/* do a quick check if we have any expired items in the tail.. */int tries = 5;int tried_alloc = 0;item *search;void *hold_lock = NULL;rel_time_t oldest_live = settings.oldest_live;search = tails[id];/* We walk up *only* for locked items. Never searching for expired.* Waste of CPU for almost all deployments */for (; tries > 0 && search != NULL; tries--, search=search->prev) {uint32_t hv = hash(ITEM_key(search), search->nkey, 0);/* Attempt to hash item lock the "search" item. If locked, no* other callers can incr the refcount*//* FIXME: I think we need to mask the hv here for comparison? */if (hv != cur_hv && (hold_lock = item_trylock(hv)) == NULL)continue;/* Now see if the item is refcount locked */if (refcount_incr(&search->refcount) != 2) {refcount_decr(&search->refcount);/* Old rare bug could cause a refcount leak. We haven't seen* it in years, but we leave this code in to prevent failures* just in case */if (search->time + TAIL_REPAIR_TIME < current_time) {itemstats[id].tailrepairs++;search->refcount = 1;do_item_unlink_nolock(search, hv);}if (hold_lock)item_trylock_unlock(hold_lock);continue;}/* Expired or flushed *//**检查LRU尾部的item是否超时,如果超时直接,返回这个item即可**/if ((search->exptime != 0 && search->exptime < current_time)|| (search->time <= oldest_live && oldest_live <= current_time)) {itemstats[id].reclaimed++;if ((search->it_flags & ITEM_FETCHED) == 0) {itemstats[id].expired_unfetched++;}it = search;slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), ntotal); do_item_unlink_nolock(it, hv);/* Initialize the item block: */it->slabs_clsid = 0;} else if ((it = slabs_alloc(ntotal, id)) == NULL) { /*尝试去slab中申请一个新的item*/tried_alloc = 1;if (settings.evict_to_free == 0) {/*如果在slab中申请失败,并且不允许LRU 替换策略*/itemstats[id].outofmemory++;} else {/*如果在slab申请失败,但是允许LRU策略,那么就从LRU队尾取出一个item*/itemstats[id].evicted++;itemstats[id].evicted_time = current_time - search->time;if (search->exptime != 0)itemstats[id].evicted_nonzero++;if ((search->it_flags & ITEM_FETCHED) == 0) {itemstats[id].evicted_unfetched++;}it = search;slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), ntotal);do_item_unlink_nolock(it, hv);/* Initialize the item block: */it->slabs_clsid = 0;/* If we've just evicted an item, and the automover is set to* angry bird mode, attempt to rip memory into this slab class. * TODO: Move valid object detection into a function, and on a* "successful" memory pull, look behind and see if the next alloc * would be an eviction. Then kick off the slab mover before the * eviction happens.*/if (settings.slab_automove == 2)slabs_reassign(-1, id);}}refcount_decr(&search->refcount);/* If hash values were equal, we don't grab a second lock */if (hold_lock)item_trylock_unlock(hold_lock);break;}if (!tried_alloc && (tries == 0 || search == NULL))it = slabs_alloc(ntotal, id);if (it == NULL) {itemstats[id].outofmemory++;mutex_unlock(&cache_lock);return NULL;}assert(it->slabs_clsid == 0);assert(it != heads[id]);/* Item initialization can happen outside of the lock; the item's already * been removed from the slab LRU.*/it->refcount = 1; /* the caller will have a reference */mutex_unlock(&cache_lock);it->next = it->prev = it->h_next = 0;it->slabs_clsid = id;DEBUG_REFCNT(it, '*');it->it_flags = e_cas ? ITEM_CAS : 0;it->nkey = nkey;it->nbytes = nbytes;memcpy(ITEM_key(it), key, nkey);it->exptime = exptime;memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix);it->nsuffix = nsuffix;return it;}请注意:我刚开始读这段代码的时候有个最不清楚的地方就是那个for循环好像执行了5次,如果这5次for循环都没找到过期的item,那么岂不是会调用slab_alloc函数5次,重复分配了5次item吗?答案:后来仔细一看,原来在for循环的最后一行代码有个break语句,那么这就说明其实for循环里面的语句最多执行一次,也就不会有上面的问题了。
Memcached 源码分析--命令流程分析一、执行命令首先是启动memcached 自带参数如下:[plain] view plain copy print?在CODE上查看代码片派生到我的代码片<span style="font-size:18px;">-p <num> 设置TCP端口号(默认设置为: 11211)-U <num> UDP监听端口(默认: 11211, 0 时关闭)-l <ip_addr> 绑定地址(默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问)-c <num> max simultaneous connections (default: 1024)-d 以daemon方式运行-u <username> 绑定使用指定用于运行进程<username>-m <num> 允许最大内存用量,单位M (默认: 64 MB)-P <file> 将PID写入文件<file>,这样可以使得后边进行快速进程终止, 需要与-d 一起使用</span>#$: ./usr/local/bin/memcached -d -u root -l 192.168.10.156 -m 2048 -p 12121客户端通过网络方式连接:telnet 192.168.10.156 12121然后就可以操作命令、常见命令如下:[plain] view plain copy print?在CODE上查看代码片派生到我的代码片<span style="font-size:18px;">setaddreplacegetdelete</span>格式如下:[plain] view plain copy print?在CODE上查看代码片派生到我的代码片<span style="font-size:18px;">command <key> <flags> <expiration time> <bytes><value>参数说明如下:command set/add/replacekey key 用于查找缓存值flags 可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息expiration time 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)bytes 在缓存中存储的字节点value 存储的值(始终位于第二行)</span>二、命令执行流程代码分析首先看一下工作线程中的命令数据结构:/*** The structure representing a connection into memcached.*/typedef struct conn conn;非常重要的几个参数:char * rbuf:用于存储客户端数据报文中的命令。
Memcached内存管理源码阅读meache能举行迅速地查找和良好的内存管理,得益于良好的hash查找和内存管理技巧.这两项功能主要由assoc.c和slab.c这两个文件来实现. 下面具体地分析一下每行代码实现slab.cdefine POWER_SMALLEST1 //slabclass数组的最小下标(slabclass 主要是来保存分配好的内存)define POWER_LARGEST 200 //slabclass数组的最大下标define POWER_BLOCK 1048576 //每一个chunk的最大值defineCHUNK_ALIGN_BYTES 8 //内存对其define DONT_PREALLOC_SLABS //不采纳事前分配内存/* powers-of-N alloion suctures *//*管理内存的主要数据结构, 搞清晰这个数据结构对囫囵内存的用法,分配,释放都很重要*/typef struct { unsigned int size; /* sizes of items */ //该结构保存的item的size大小,即最多能保存多大的数据 unsigned int perslab; /* how many items per slab */ //分配好一个slab 后,该slab可以存储多少个大小size的 vo **slots; /* list of item ptrs */ //回收回归后,内存的数组 unsigned int sl_total; /* size of previous array */ //目前总共有多少个空余的内存块 unsigned int sl_curr; /* first slot */ //目前已经用法到了多少个内存块void *end_page_ptr; /* pointer to nt free item at end of page, or 0 */ //每个slab中,可用法的地址 unsigned int end_page_free; /* number of items remaining at end of last alloced page */ //该slab中,可用法的内存块大小 unsigned int slabs; /* how many slabs were ald for this class */ //已经用法slab void **slab_list; /* array of slab pointers */ //保存每个slab的起始地址unsigned int list_size; /* size of prev array */ //总共有多少个slab unsigned int ing; /* index+1 of dying slab, or zero if none */} slabclass_t;ic slabclass_t slabclass[POWER_LARGEST + 1]; //核心的slabclass变量, 保存全部的内存static size_tmem_limit = 0; //限制memcache内存的用法的大小static size_t第1页共2页。