删除过期Item
Memcached为每个item设置一个过期时间,但不是到期就把item从内存删除,而是访问item时,如果到了有效期,才把item从内存中删除。
item *do_item_get_notedeleted(const char*key,const size_t nkey,bool *delete_locked){
item *it = assoc_find(key ,nkey);
if(delete_locked) *delete_locked =false;
if(it != NULL && (it ->it_flags & ITEM_DELETED)){
if(!item_delete_lock_over(it)){
if(delete_locked)*delete_locked = true;
it = null;
}
}
if(it != null &&settings.oldest_live != && settings.oldest_live <= current_time&& it -> time <= settings.oldest_live){
do_item_unlink(it);
it = null;
}
/*------------------------------------------*/
if(it != null && it ->exptime != && it -> exptime <= current_time){
do_item_unlink(it);
it = null;
}
/*------------------------------------------*/
if(!it = null ){
it -> refcount ++;
DEBUG_REFCNT(it,'+');
}
return it;
}
使用do_item_get_notedeleted函数在memcached中查找指定的item,从上面代码可知,当item过期时间早于当前时间时,便会删除此item。
注: 延迟删除过期的iten到查找进行,可以提高memcached的效率。这样不必每时每刻检查过期item,从而提高CPU工作效率。这种模式称之为惰性失效。
使用LRU算法淘汰数据
当Memcached使用内存大于设置的最大内存使用时,为了腾出内存空间来存放新的数据项,Memcached会启动LRU算法淘汰旧的数据项。
使用slabs_alloc函数申请内存失败时,就开始淘汰数据了。淘汰规则是,从数据项列表尾部开始遍历,在列表中查找一个引用计数器为0的item,把此item释放掉。
为什么要从item列表尾部开始遍历呢? 因为memcached会把刚刚访问过的item放到item列表头部,所以尾部的item都是没有或很少访问的,这就是LRU算法的精髓。
如果在item列表找不到计数器为0的item,就查找一个3小时没有访问过的item。把他释放,如果还是找不到,就返回NULL(申请内存失败)。
从上面的分析可以知道,当内存不足时,memcached会把访问比较少或者一段时间没有访问的item淘汰,以便腾出内存空间存放新的item。
注:即使某个key设置的是永久有效,也一样会被删除,即为:老数据被踢现象。