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,让我们可以针对我们数据特点进行调优,让其更好的为我所用. 首先需要我们先了解两 ...
随机推荐
- List、Set、Map 之间的区别是什么?(未完成)
List.Set.Map 之间的区别是什么?(未完成)
- 类的命名空间与卸载详解及jvisualvm使用
类的命名空间详解: 在上一次[https://www.cnblogs.com/webor2006/p/9108301.html]最后实验中有一个违背咱们理解的,这里回顾一下: 也就是说,"某 ...
- 【Codeforces】Orz Panda Cup
大大出的题 大大经常吐槽没有人补,所以我决定做一个 A. APA of Orz Pandas 题意:给你一个包含+-*/%和()的表达式,让你把它转化成java里BigInteger的形式 大概就像这 ...
- golang embedded structs
golang 中把struct 转成json格式输出 package main import ( "encoding/json" "fmt" ) type Pe ...
- JavaScript教程——实例对象与 new 命令
典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念.所谓“类”就是对象的模板,对象就是“类”的实例.但是,JavaScript 语言的对象体系,不是基于“类”的,而 ...
- python_三元运算符
三元运算又称三目运算,是对简单的条件语句的简写 简单条件语句: if 条件成立: val = 1 else: val = 2 改成三元运算: val = 1 if 条件成立 else 2 举例: a ...
- 用jquery实现Ping测试网络连接性
jquery的ping插件://要用的需要明白代码及自己改些地方 (function($) { $.fn.ping = function(options) { var opts = ...
- mongodb命令---创建数据库,插入文档,更新文档记录
创建数据库----基本就是使用隐式创建 例如 use 你定义的数据库名, use dingsmongo 如果你使用的是studio 3T软件,那直接选中右侧的地址栏点击右键选择Add Databas ...
- 【Android-布局复用】 多个界面复用一个布局文件(二)
多个界面复用一个布局界面 ,如何找到复用布局文件中的控件的id? 举个栗子: 1. layout_common.xml 复用的布局文件,如何找到button 的id? <?xml versio ...
- .net core 自动注入。。。。懵逼。。
using Microsoft.AspNetCore.Http; using System.Globalization; using System.Threading.Tasks; namespace ...