memcache不会释放内存,而是重新利用。

在缓存的清除方面,memcache是不释放已分配内存。当已分配的内存所在的记录失效后,这段以往的内存空间,memcache只会重复利用。

memcached的内存回收机制不是说你设置的key到了生命周期就自动从内存中清除的,这个时候必须有一个新的对象入驻请求这个大小的chunk或者 这个过期的对象被get的时候才会清除。

那当所有给memcache的内存都被占用了,这个时候,memcache有两个设置,要么报错,要么,就是用 LRU方法,把last recently used的数据清除出去,也就是删除近段时间最少使用的同规格chunk。
 
这个时候就会引发应外一个问题,就是当你chunk大小设置不合理的时候,比如slab20 chunk大小非常大,一开始占用了很多内存,但是之后不论是否过期,不被再次利用到的时候就一直处于内存中,这样,当比较小的slab1中的chunk 满了,也没有内存新建slab并分割和slab1同样规格的chunk的时候,memcached就要启动LRU,来清理这个slab下的数据。那这种情 况就会造成在内存的极大程度浪费和cache命中率下降,是某些关键性的数据总是在内存中进进出出,得不到持久的保存。
这个时候我们可以调整factor参数,让chunk的大小达到我们的需要,这个需要根据业务来做。
那slab数量,growth factor大小,LRU频率以及空间浪费情况可以估计出来如下结果:
growth factor↑ slab数量 ↓ LRU频率↓ 空降浪费↑
growth factor↓ slab数量 ↑ LRU频率↑ 空降浪费↓
 
关于LRU
我们知道c++里分配内存有两种方式,预先分配和动态分配,显然,预先分配内存会使程序比较快,但是它的缺点是不能有效利用内存,而动态分配可以有效利用 内存,但是会使程序运行效率下降,memcached的内存分配就是基于以上原理,显然为了获得更快的速度,有时候我们不得不以空间换时间。
我启动一个memcached进程,占用内存100m,再打开telnet,telnet localhost 11211,连接上memcache之后,输入stats  slabs,回车,出现如下数据:
STAT :chunk_size
STAT :chunks_per_page
STAT :total_pages
STAT :total_chunks
STAT :used_chunks
STAT :free_chunks
STAT :free_chunks_end
STAT :chunk_size
STAT :chunks_per_page
STAT :total_pages
STAT :total_chunks
STAT :used_chunks
STAT :free_chunks
STAT :free_chunks_end
STAT :chunk_size
STAT :chunks_per_page
STAT :total_pages
STAT :total_chunks
STAT :used_chunks
STAT :free_chunks
STAT :free_chunks_end

以上就是前3个slab得详细信息
chunk_size表示数据存放块得大小,chunks_per_page表示一个内存页page中拥有得chunk得数
量,total_pages表示每个slab下page得个数。total_chunks表示这个slab下chunk得总数(=total_pages
*
chunks_per_page),used_chunks表示该slab下已经使用得chunk得数量,free_chunks表示该slab下还可以
使用得chunks数量。

从上面得示例slab 1一共有1m得内存空间,而且现在已经被用完了,slab2也有1m得内存空间,也被用完了,slab3得情况依然如此。

而且从这3个slab中chunk得size可以看出来,第一个chunk为80b,第二个是100b,第3个是128b,基本上后一个是前一个得
1.25倍,但是这个增长情况我们是可以控制得,我们可以通过在启动时得进程参数 –f来修改这个值,比如说 –f
1.1表示这个增长因子为1.1,那么第一个slab中得chunk为80b得话,第二个slab中得chunk应该是80*1.1左右。

解释了这么多也该可以看出来我遇到得问题得原因了,如果还看不出来,那我再补充关键的一句:memcached中新的value过来存放的地址是
该value的大小决定的,value总是会被选择存放到chunk与其最接近的一个slab中,比如上面的例子,如果我的value是80b,那么我这
所有的value总是会被存放到1号slab中,而1号slab中的free_chunks已经是0了,怎么办呢,如果你在启动memcached的时候
没有追加-M(禁止LRU,这种情况下内存不够时会out of
memory),那么memcached会把这个slab中最近最少被使用的chunk中的数据清掉,然后放上最新的数据。这就解释了为什么我的内存还有
40%的时候LRU就执行了,因为我的其他slab中的chunk_size都远大于我的value,所以我的value根本不会放到那几个slab中,
而只会放到和我的value最接近的chunk所在的slab中(而这些slab早就满了,郁闷了)。这就导致了我的数据被不停的覆盖,后者覆盖前者。

问题找到了,解决方案还是没有找到,因为我的数据必须要求命中率时100%,我只能通过调整slab的增长因子和page的大小来尽量来使命中率
接近100%,但是并不能100%保证命中率是100%(这话怎么读起来这么别扭呢,自我检讨一下自己的语文水平),如果您说,这种方案不行啊,因为我的
memcached server不能停啊,不要紧还有另外一个方法,就是memcached-tool,执行move命令,如:move 3
1,代表把3号slab中的一个内存页移动到1号slab中,有人问了,这有什么用呢,比如说我的20号slab的利用率非常低,但是page却又很多,
比如200,那么就是200m,而2好slab经常发生LRU,明显page不够,我就可以move 20
2,把20号slab的一个内存页移动到2号slab上,这样就能更加有效的利用内存了(有人说了,一次只移动一个page,多麻烦啊?ahuaxuan
说,还是写个脚本,循环一下吧)。

有人说不行啊,我的memcache中的数据不能丢失啊,ok,试试新浪的memcachedb吧,虽然我没有用过,但是建议大家可以试试,它也使利用
memcache协议和berkeleyDB做的(写到这里,我不得不佩服danga了,我觉得它最大的贡献不是memcache
server本身,而是memcache协议),据说它被用在新浪的不少应用上,包括新浪的博客。

补充,stats slab命令可以查看memcached中slab的情况,而stats命令可以查看你的memcached的一些健康情况,比如说命中率之类的,示例如下:

STAT pid
STAT uptime
STAT time
STAT version 1.2.
STAT pointer_size
STAT curr_items
STAT total_items
STAT bytes
STAT curr_connections
STAT total_connections
STAT connection_structures
STAT cmd_get
STAT cmd_set
STAT get_hits
STAT get_misses
STAT bytes_read
STAT bytes_written
STAT limit_maxbytes

从上面的数据可以看到这个memcached进程的命中率很好,get_misses低达0个,怎么回事啊,因为这个进程使我刚启动的,我只用 telnet连了一下,所以curr_connections为1,而total_items为0,因为我没有放数据进去,get_hits为0,因为我 没有调用get方法,最后的结果就是misses当然为0,哇哦,换句话说命中率就是100%,又yy了。

该到总结的时候了,从这篇文章里我们可以得到以下几个结论:

结论一,memcached得LRU不是全局的,而是针对slab的,可以说是区域性的。

结论二,要提高memcached的命中率,预估我们的value大小并且适当的调整内存页大小和增长因子是必须的。

结论三,带着问题找答案理解的要比随便看看的效果好得多。

参考:http://ahuaxuan.iteye.com/blog/225692

memcache的内存回收机制的更多相关文章

  1. Android 操作系统的内存回收机制(转载)

    Android 操作系统的内存回收机制(转载) Android APP 的运行环境 Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对 ...

  2. JVM内存回收机制简述

    JVM内存回收机制涉及的知识点太多了,了解越多越迷糊,汗一个,这里仅简单做个笔记,主要参考<深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)> 目前java的jdk默认虚拟机为H ...

  3. JVM内存回收机制

    1. JVM内存回收机制简述 http://www.cnblogs.com/lzrabbit/p/3826738.html

  4. Android 操作系统的内存回收机制[转]

    转自:http://www.ibm.com/developerworks/cn/opensource/os-cn-android-mmry-rcycl/ Android APP 的运行环境 Andro ...

  5. Redis的内存回收机制

    Redis的内存回收机制 2018年01月16日 17:11:48 chs007chs 阅读数:1172   Redis的内存回收机制主要体现在一下两个方面: 删除过期时间的键对象 删除过期键对象 : ...

  6. Java技术专题之JVM逻辑内存回收机制研究图解版

    一.引言 JVM虚拟机内存回收机曾迷惑了不少人,文本从JVM实现机制的角度揭示JVM内存回收的原理和机制. 一.Java平台逻辑架构 二.JVM物理结构 通过从JVM物理结构图我们可以看到: 1.JV ...

  7. php内存回收机制的学习

    今天朋友去面试,回来问了一下怎么样,结果他说一脸懵逼,看来我们平时还是学习的太少了啊.于是比较好奇,果断问了一下都有哪些问题,朋友说第一个问题就是“描述PHP的垃圾回收机制”,我当时听了也是一脸茫然, ...

  8. Java进阶3. 内存回收机制

    Java进阶3. 内存回收机制 20131029 前言: 学过C++的都知道,C++中内存需要程序员自己维护.说道这里,很多开发的同学就感觉很痛苦,当他转向Java的时候,就会说你看Java多好啊,程 ...

  9. Qt ------ 内存回收机制、new对象的回收

    写在前面的总结: 建议:对于不能指定父对象的对象(对象通过moveToThread()移入其他线程.没有继承QObject的类产生的对象),在其他线程通过deleteLater()内存回收,其他通过指 ...

随机推荐

  1. drbd初探及Heartbeat+DRBD+MySQL

    1,drbd快速入门 http://www.mingxiao.info/article/?id=39#__RefHeading___Toc1114_501652171 2.Heartbeat+DRBD ...

  2. Web API路由和动作选择

    前言 本文描述ASP.NET Web API如何把一个HTTP请求路由到控制器的一个特定的Action上.关于路由的总体概述可以参见上一篇教程 http://www.cnblogs.com/aehyo ...

  3. python中class 的一行式构造器

    好处:避免类初始化时大量重复的赋值语句 用到了魔法__dict__ # 一行式构造器 class Test(): # 初始化 def __init__(self, a, b, c=2, d=3, e= ...

  4. [CareerCup] 9.3 Magic Index 魔法序号

    9.3 A magic index in an array A[0.. .n-1] is defined to be an index such that A[i] = i. Given a sort ...

  5. Linux第六次学习笔记

    存储器层次结构 存储器系统是一个具有不同容量.成本和访问时间的存储设备的层次结构. CPU寄存器保存着最常用的数据. 主存储器(简称主存)暂时存放存储在容量较大的.慢速磁盘上的数据. 高速缓存存储器作 ...

  6. 4.HBase In Action 第一章-HBase简介(1.1.2 数据创新)

    As we now know, many prominent internet companies, most notably Google, Amazon, Yahoo!, and Facebook ...

  7. 开始学习node.js了,第一节,fs文件系统 【fs.rename】重命名文件/文件夹

    var fs=require('fs');fs.rename('c:\\a','c:\\a2',function(err){ if(err) console.log('error:'+err);}); ...

  8. 编译到底做了什么(***.c -> ***.o的过程)

     (第一次写博客,好激动的说.......)   我们知道,一个程序由源代码到可执行文件往往由这几步构成: 预处理(Prepressing)-> 编译(Compilation)-> 汇编( ...

  9. MVC 依赖注入

    本人主要是写给我自己看的,文章没有过多的解释,只留下步骤. 目的:面向接口编程,做到低耦合,高内聚 1.利用Nuget 管理工具,安装Ninject. 2.随便新建一个接口和一个实现类,我在此项目中是 ...

  10. Dandelion - Distributed Computing on GPU Clusters

    linq on GPUs 非常期待中 看起来很cool,期望早点面世