台州网站建设seo,wordpress 数据库ip,共享办公商业租赁网站模板,17网站一起做网店不发货一. 内存回收  因为C语言不具备内存回收功能#xff0c;所以Redis在自己的对象系统中构建了一个引用计数技术实现内存回收机制。通过这一机制#xff0c;程序可以通过跟踪对象的引用计数信息#xff0c;在适当的时候自动释放对象并进行内存回收。 内每一个对象的引用计数信息…一. 内存回收  因为C语言不具备内存回收功能所以Redis在自己的对象系统中构建了一个引用计数技术实现内存回收机制。通过这一机制程序可以通过跟踪对象的引用计数信息在适当的时候自动释放对象并进行内存回收。 内每一个对象的引用计数信息由redisObject结构的refcount属性记录 
typedef struct redisObject {unsigned type:4;unsigned encoding:4;unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or* LFU data (least significant 8 bits frequency* and most significant 16 bits access time). */int refcount;void *ptr;
} robj;对象的引用计数信息会随着对象的使用状态而不断变化 
在创建一个新对象时引用计数的值会被初始化为1。当对象被一个新程序使用时他的引用计数会被增1。当对象不被程序使用时他的引用计数会被减1。当对象的引用计数值变为0时对象所占有的内存会被释放掉。 下面是对引用计数进行操作的接口 
//创建对象
robj *createObject(int type, void *ptr);
robj *createStringObject(const char *ptr, size_t len);
robj *createRawStringObject(const char *ptr, size_t len);
robj *createEmbeddedStringObject(const char *ptr, size_t len);
robj *createStringObjectFromLongLong(long long value);
robj *createStringObjectFromLongLongForValue(long long value);
robj *createStringObjectFromLongDouble(long double value, int humanfriendly);
robj *createQuicklistObject(void);
robj *createZiplistObject(void);
robj *createSetObject(void);
robj *createIntsetObject(void);
robj *createHashObject(void);
robj *createZsetObject(void);
robj *createZsetZiplistObject(void);
robj *createStreamObject(void);
robj *createModuleObject(moduleType *mt, void *value);//对引用计数加1
void incrRefCount(robj *o) {if (o-refcount  OBJ_FIRST_SPECIAL_REFCOUNT) {o-refcount;} else {if (o-refcount  OBJ_SHARED_REFCOUNT) {/* Nothing to do: this refcount is immutable. */} else if (o-refcount  OBJ_STATIC_REFCOUNT) {serverPanic(You tried to retain an object allocated in the stack);}}
}
//对引用计数减1减为0时释放对象内存
void decrRefCount(robj *o) {if (o-refcount  1) {switch(o-type) {case OBJ_STRING: freeStringObject(o); break;case OBJ_LIST: freeListObject(o); break;case OBJ_SET: freeSetObject(o); break;case OBJ_ZSET: freeZsetObject(o); break;case OBJ_HASH: freeHashObject(o); break;case OBJ_MODULE: freeModuleObject(o); break;case OBJ_STREAM: freeStreamObject(o); break;default: serverPanic(Unknown object type); break;}zfree(o);} else {if (o-refcount  0) serverPanic(decrRefCount against refcount  0);if (o-refcount ! OBJ_SHARED_REFCOUNT) o-refcount--;}
} 对象的整个生命周期可以划分为创建对象操作对象释放对象三个阶段。 
二. 对象共享 Redis除了用于实现引用计数内存回收机制之外对象的引用计数属性还带由对象共享的作用。 举个例子假设键A创建一个包含整数值100的字符串对象作为值对象如果这时键B也要创建一个同样保存了整数值100的字符串对象作为值对象。Redis服务器的做法是让键A和键B共享同一个字符串对象。也就是将数据库的键的值指针指向一个现有的值对象将共享的值对象的引用计数加一。 这样的共享对象机制的作用是节约内存。  目前来说Redis会在初始化服务器时创建一万个字符串对象这些对象包含从0到9999的所有整数值当服务器需要用到值为0到9999的字符串对象时服务器会使用到这些共享对象。而不是新创建对象。 注意创建共享字符串对象的数量可以通过redis.h/REDIS_SHARED_INTEGERS常量修改。 下面的命令佐证了只有值是0到9999整数的字符串对象作为共享对象 
127.0.0.1:6379 set A 10000
OK
127.0.0.1:6379 OBJECT REFCOUNT A
(integer) 1
127.0.0.1:6379 set B 10000
OK
127.0.0.1:6379 OBJECT REFCOUNT A
(integer) 1
127.0.0.1:6379 OBJECT REFCOUNT B
(integer) 1 另外这些共享对象不单单只有字符串键可以使用那些在数据结构嵌套了字符串对象的对象(linkedlist编码的列表对象hashtable编码的哈希对象hashtable编码的集合对象zset编码的有序集合对象)都可以使用这些共享对象。 为什么Redis不包含字符串的对象         当服务器考虑将一个共享对象设置为键的值对象时程序需要先检查给定的共享对象和键想创建的目标对象是否完全相同只有在共享对象和目标对象完全相同的情况下程序才会将共享对象用作键的值对象。当共享对象保存的值越复杂验证共享对象和目标对象是否相同所需要的复杂度越高。 假如共享对象是整数值的字符串对象那么验证操作的复杂度为O(1)。假如共享对象是字符串值的字符串对象那么验证操作复杂度为O(N)。假如共享对象是包含了多个值(或对象)的对象比如列表对象或哈希对象那么验证操作的复杂度将会是O(N^2)。         因此尽管共享对象可以节约内存但是为了效率着想Redis只对包含整数值的字符串对象进行共享。 三. 对象时间空转时长 redisObject对象中还有一个属性lru记录了对象最后一次被命令程序访问的时间。OBJECT IDLETIME命令可以打印出给定键的空转时长这个空转时长就是通过将当前时间减去键的值对象的lru时间计算出来的。OBJECT IDLETIME命令在执行时不会修改lru属性。 对象的空转时长出来可以使用OBJECT IDLETIME命令查看外另外一个作用是如果服务器打开了maxmemory选项并且服务器的回收算法为volatile-lru或者allkeys-lru那么当服务器占用的内存数超过maxmemory的值时空转时长较高的那部分键会被服务器优先释放从而回收内存。