memcached-slab内存管理
一、Memcache内存分配机制
关于这个机制网上有很多解释的,我个人的总结如下。
Page为内存分配的最小单位。
Memcached 的内存分配以page为单位,默认情况下一个page是1M,可以通过-I参数在启动时指定。如果需要申请内存 时,memcached会划分出一个新的page并分配给需要的slab区域。page一旦被分配在重启前不会被回收或者重新分配(page ressign已经从1.2.8版移除了) 
Slabs划分数据空间。
Memcached
并不是将所有大小的数据都放在一起的,而是预先将数据空间划分为一系列slabs,每个slab只负责一定范围内的数据存储。如
下图,每个slab只存储大于其上一个slab的size并小于或者等于自己最大size的数据。例如:slab 3只存储大小介于137 到 224
bytes的数据。如果一个数据大小为230byte将被分配到slab
4中。从下图可以看出,每个slab负责的空间其实是不等的,memcached默认情况下下一个slab的最大值为前一个的1.25倍,这个可以通过修
改-f参数来修改增长比例。 
Chunk才是存放缓存数据的单位。
Chunk
是一系列固定的内存空间,这个大小就是管理它的slab的最大存放大小。例如:slab 1的所有chunk都是104byte,而slab
4的所有chunk都是280byte。chunk是memcached实际存放缓存数据的地方,因为chunk的大小固定为slab能够存放的最大值,
所以所有分配给当前slab的数据都可以被chunk存下。如果时间的数据大小小于chunk的大小,空余的空间将会被闲置,这个是为了防止内存碎片而设
计的。例如下图,chunk size是224byte,而存储的数据只有200byte,剩下的24byte将被闲置。 
Slab的内存分配。
Memcached在启动时通过-m指定最大使用内存,但是这个不会一启动就占用,是随着需要逐步分配给各slab的。
如果一个新的缓存数据要被存放,memcached首先选择一个合适的slab,然后查看该slab是否还有空闲的chunk,如果有则直接存放进去;如
果没有则要进行申请。slab申请内存时以page为单位,所以在放入第一个数据,无论大小为多少,都会有1M大小的page被分配给该slab。申请到
page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成了一个chunk的数组,在从这个chunk数组中选择一个用于存储
数据。如下图,slab 1和slab 2都分配了一个page,并按各自的大小切分成chunk数组。 
Memcached内存分配策略。
综合上面的介绍,memcached的内存分配策略就是:按slab需求分配page,各slab按需使用chunk存储。
这里有几个特点要注意,
Memcached分配出去的page不会被回收或者重新分配Memcached申请的内存不会被释放slab空闲的chunk不会借给任何其他slab使用

知道了这些以后,就可以理解为什么总内存没有被全部占用的情况下,memcached却出现了丢失缓存数据的问题了。
http://blog.csdn.net/lcli2009/article/details/22095251
http://blog.csdn.net/lcli2009/article/details/21985793
- typedef struct _stritem {
- struct _stritem *next;//item在slab中存储时,是以双链表的形式存储的,next即后向指针
- struct _stritem *prev;//prev为前向指针
- struct _stritem *h_next;//Hash桶中元素的链接指针
- rel_time_t time; //最近访问时间
- rel_time_t exptime;//过期时间
- int nbytes;//数据大小
- unsigned short refcount;//引用次数
- uint8_t nsuffix;
- uint8_t it_flags;
- uint8_t slabs_clsid;//标记item属于哪个slabclass下
- uint8_t nkey; //key的长度
- union {
- uint64_t cas;
- char end;
- } data[];//真实的数据信息
- } item;
If the new item is bigger than the size
of any existing blocks, then a new slab is created, divided up into
blocks of a suitable size. If an existing slab with the right block size
already exists, but there are no free blocks, a new slab is created.
内存页一旦被分配给slab,在memcache生命周期内不再更改,在内存总量确定的情形下,其它slab可能出现饿死现象;
algorithm is slow and conservative. If a slab class is seen as having
the highest eviction count 3 times 10 seconds apart, it will take a page
from a slab class which has had zero evictions in the last 30 seconds
and move the memory.
unsigned int size; /* 每个item大小, sizes of items */
unsigned int perslab; /* 每个page中包含多少个item , how many items per slab */
void **slots; /* 空闲的item指针, list of item ptrs */
unsigned int sl_total; /* 以分配空闲的item 个数, size of previous array */
unsigned int sl_curr; /* 当前空闲的item位置(也就是实际空闲item个数),从后往前的, first free slot */
void *end_page_ptr; /* 指向最后一个页面中空闲的item开始位置, pointer to next free item at end of page, or 0 */
unsigned int end_page_free; /* 最后一个页面,item个数, number of items remaining at end of last alloced page */
unsigned int slabs; /* 实际使用slab(page)个数 how many slabs were allocated for this class */
void **slab_list; /* 所有page的指针, array of slab pointers */
unsigned int list_size; /* 已经分配page指针个数,size of prev array */
unsigned int killing; /* index+1 of dying slab, or zero if none */
size_t requested; /* 所有被使用了的内存的大小, The number of requested bytes */
} slabclass_t;


do_item_remove(it);//删除item
do_item_remove
slabs_free(it, ntotal, clsid);//slabclass结构执行释放
it->it_flags |= ITEM_SLABBED;//修改item的状态标识,修改为空闲
it->prev = 0;//断开数据链表
it->next = p->slots;
if (it->next) it->next->prev = it;
p->slots = it;
int tries = 5;//如果LRU中尝试5次还没合适的空间,则执行申请空间的操作
search = tails[id];//第id个LRU表的尾部
it = search;
......
}
it = slabs_alloc(ntotal, id);//则从内存池申请新的空间
}
// 1 最后面的页面有空间 2 空闲的地方有空间 3 分配一个新的页面
if (! (p->end_page_ptr != 0 || 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 */
//从空闲(回收)地方分配
ret = p->slots[--p->sl_curr];
} else {
/* if we recently allocated a whole page, return from that */
assert(p->end_page_ptr != NULL);
ret = p->end_page_ptr;
if (--p->end_page_free != 0) {
p->end_page_ptr = ((caddr_t)p->end_page_ptr) + p->size;
} else {
p->end_page_ptr = 0;
}
}
if (ret) {
p->requested += size;
MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret);
} else {
MEMCACHED_SLABS_ALLOCATE_FAILED(size, id);
}
return ret;
}
memcached-slab内存管理的更多相关文章
- memcached的内存管理与删除机制
memcached的内存管理与删除机制 简介 注意:Memcache最大的value也只能是1M的空间,超过1M的数据无法保存(修改memcache源代码). 注意:内存碎片化永远都存在,只是哪一 ...
- nginx slab内存管理
本来这一篇作为nginx系列的开头是不合适的,不过由于nginx进程框架自己的梳理还没完成,这部分又刚好整理完了,就从这开始吧.这儿谈的是nginx的slab的内存管理方式,这种方式的内存管理在ngi ...
- Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制
Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制 http://w ...
- memcached整理の内存管理及删除机制
内存的碎片化 如果用C语言直接malloc,free来向操作系统申请和释放内存时,在不断申请和释放的过程中,形成了一些很小的内存片段,无法再利用.这种空闲但无法利用内存的现象称为内存的碎片化. sla ...
- memcached 的内存管理与删除机制
1:内存的碎片化 如果用 c 语言直接 malloc,free 来向操作系统申请和释放内存时, 在不断的申请和释放过程中,形成了一些很小的内存片断,无法再利用. 这种空闲,但无法利用内存的现象,--- ...
- 关于linux kernel slab内存管理的一点思考
linux kernel 内存管理是个很大的话题,这里记录一点个人关于slab模块的一点思考总结. 有些书把slab介绍成高速缓存,这会让人和cache,特别是cpu cache混淆,造成误解.sla ...
- Memcached 之内存管理与删除机制
一.内存的碎片化 如果用c语言直接 malloc,free 来向操作系统申请和释放内存时,在不断的申请和释放过程中,形成了一些很小的内存片断,无法再利用,这种空闲,但无法利用内存的现象称为内存的碎片化 ...
- memcached 内存管理 分析(转)
Memcached是一个高效的分布式内存cache,了解memcached的内存管理机制,便于我们理解memcached,让我们可以针对我们数据特点进行调优,让其更好的为我所用.这里简单谈一下我对me ...
- Memcached源码分析之内存管理
先再说明一下,我本次分析的memcached版本是1.4.20,有些旧的版本关于内存管理的机制和数据结构与1.4.20有一定的差异(本文中会提到). 一)模型分析在开始解剖memcached关于内存管 ...
- Memcached 内存管理详解
Memcached是一个高效的分布式内存cache,了解memcached的内存管理机制,便于我们理解memcached,让我们可以针对我们数据特点进行调优,让其更好的为我所用. 首先需要我们先了解两 ...
随机推荐
- P4151 最大XOR和路径 线性基
题解见:https://www.luogu.org/problemnew/solution/P4151 其实就是找出所有环 把环上所有边异或起来得到的值扔到线性基里面 然后随便走一条从1~n的链 最后 ...
- Selenium&Appium四种等待方式
一.摘要 本博文主要介绍自动化测试中,无论是selenium或是Appium的四种等待方式,合理的使用等待对代码的稳定性,测试效率都有很大的提高 隐式等待:是在尝试发现某个元素的时候,如果没能立刻发现 ...
- PHP 按照指定数量分割数组
<?php /** * 系统辅助类 * @date 2019年7月2日 * @comment * */ class SystemUtils { private static $_instance ...
- FFmpeg常用命令学习笔记(一)基本信息查询命令
笔者才开始学习音视频开发,FFmpeg学习笔记系列主要是从慕课网李超老师的FFmpeg音视频核心技术精讲与实战课程学习的心得体会. FFmpeg音视频核心技术精讲与实战:https://coding. ...
- loj515 「LibreOJ β Round #2」贪心只能过样例[bitset+bool背包]
由于bitset极其不熟练且在实际题目中想不起来运用它来优化,于是练了几道题. 这题是一个分组的bool背包,每组必须选一个,暴力的话是$O(n^5)$. 如果dp数组不要一维滚动的话,有两种枚举方法 ...
- Codeforces Round #509 (Div. 2) E. Tree Reconstruction(构造)
题目链接:http://codeforces.com/contest/1041/problem/E 题意:给出n - 1对pair,构造一颗树,使得断开其中一条边,树两边的最大值为 a 和 b . 题 ...
- .net System.Net.Mail 之用SmtpClient发送邮件Demo
private static bool sendMail() { try { //接收人邮箱 string SendTo = "XXXXX@163.com ...
- 多线程 submit与execute区别
(1)可以接受的任务类型 submit: execute: 可以看出: execute只能接受Runnable类型的任务 submit不管是Runnable还是Callable类型的任务都可以接受,但 ...
- 【luoguP4124 】[CQOI2016]手机号码
题目描述 人们选择手机号码时都希望号码好记.吉利.比如号码中含有几位相邻的相同数字.不含谐音不吉利的数字等.手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售.为了便于前 ...
- jQuery系列(四):jQuery的属性操作
jquery的属性操作模块分为四个部分:html属性操作,dom属性操作,类样式操作和值操作 html属性操作:是对html文档中的属性进行读取,设置和移除操作.比如attr().removeAttr ...