部分摘自:http://blog.youkuaiyun.com/qq_28602957/article/details/52799117
https://www.jianshu.com/p/e0676591f5ac
Slab Allocator 缓解内存碎片化
Memcached利用Slab Allocator机制管理内存。
预先把内存划分成数个大小1M的slab class仓库,再把每个仓库切分成不同尺寸的小块(chunk)。并把尺寸相同的块分成组(chunk的集合)。(如下图)
memcached 根据收到的数据的大小, 选择最适合数据大小的chunk组
slab allocator 还有重复使用已分配的内存的目的,比如如果有 100byte 的内容要存,但 112 大小的仓库中的 chunk 满了 并不会寻找更大的,如 144 的仓库来存储,而是把 112 仓库的旧数据踢掉!
Slab Allocator 解决了当初的内存碎片问题,但新的机制也给 memcached 带来了新的问题。
因为不能自定义chunk的大小,所以无法彻底解决chunk空间浪费问题。比如分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将 100 字节的数据缓存到 128 字节的 chunk 中,剩余的 28 字节就浪费了 。
问题缓解: 如果预先知道客户端发送的数据的公用的大小,或者仅缓存大小相同的数据的情况下。只要使用适合数据大小的组的列表,就可以减少浪费。
即: 通过缓存中item长度进行统计,通过参数调整slab class大小的增长速度,即增长因子(growth factor),从而制定合理的chunk大小。
Grow Factor增长因子调优
memcached 在启动时可以通过f 选项指定 Growth Factor 因子, 并在某种程度上控制 slab之间的差异. 默认值为 1.25. 但是,在该选项出现之前,这个因子曾经固定为 2,称为”powers of 2”策略。
数据删除[过期数据惰性删除]
注: 延迟删除过期的iten直到查找进行,可以提高memcached的效率。这样不必每时每刻检查过期item,从而提高CPU工作效率。这种模式称之为惰性失效。
使用LRU算法淘汰数据
当Memcached使用内存大于设置的最大内存使用时,为了腾出内存空间来存放新的数据项,Memcached会启动LRU算法淘汰旧的数据项。 如果以 128byte的chunk举例, 128byte的chunk都满了, 又有新的值(长度为 120)要加入, 要剔除掉哪个数据?
使用slabs_alloc函数申请内存失败时,就开始淘汰数据了。淘汰规则是,从数据项列表尾部开始遍历,在列表中查找一个引用计数器为0的item,把此item释放掉。
为什么要从item列表尾部开始遍历呢? 因为memcached会把刚刚访问过的item放到item列表头部,所以尾部的item都是没有或很少访问的,这就是LRU算法的精髓。
如果在item列表找不到计数器为0的item,就查找一个3小时没有访问过的item。把他释放,如果还是找不到,就返回NULL(申请内存失败)。
从上面的分析可以知道,当内存不足时,memcached会把访问比较少或者一段时间没有访问的item淘汰,以便腾出内存空间存放新的item。
注:即使某个key设置的是永久有效,也一样会被删除,即为:永久数据被踢现象。