对象数据结构
前面说了Redis有很多种类型,string、hash、list、set、sort set..
但是Redis在创建这些数据结构的时候并没有直接使用这些数据结构来实现键值对数据库,Redis自己实现了一套对象结构redisObject
,先来简单看下它的数据结构
源码redis.h
#define REDIS_LRU_BITS 24
...
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
-
type:数据类型,比如string、list..这些
-
encoding:type对应的底层具体实现,比如list有ziplist和linkedlist两种
-
lru:对象没有被使用时的空闲时长(s),比如当调用get访问的时候,重置lru为0开始重新计数
set a 1 // 等待10s object idletime a // 10 get a // 1 object idletime a // 0
-
refcount:因为c语言需要自已去手动回收内存,所以redis自己实现了一套垃圾回收机制 -> 引用计数法,当对象被创建时,refcount为1,当另一个引用也使用到这个对象时,refcount+1,不使用时-1,当refcount为0时,回收这个对象使用的内存
-
ptr:对象的引用
对象的简单操作
先创建个string类型的对象,看看它有哪些方法吧
set a abc
// 查看类型,也就是redisObject的type属性
type a // string
// 查看type底层的编码实现,redisObject的encoding属性
object encoding a // embstr
// 查看引用个数,redisObject的refcount属性
object refcount a // 1
// 查看空闲时间,未使用时过了多少秒
object idletime a // 10
对象的类型与编码
编码大全:
int:整形字符串
raw:可变字符串
embstr:只读短字符串
ziplist:压缩列表
linkedlist:链表
hashtable:哈希表
intset:整型集合
skiplist:跳跃表
类型对应的编码:
string:int
、raw
、embstr
list:ziplist
、linkedlist
hash:ziplist
、hashtable
set:intset
、hashtable
sort set:ziplist
、skiplist
共享对象
垃圾回收机制的引用计数法和共享对象的实现有点关系
举个例子,先创建了一个键为A并且包含整数值100的字符串作为值对象,这时如果键B也要创建一个整数值为100的字符串作为值对象,那么现在有两种做法:
- 为键 B 新创建一个包含整数值
100
的字符串对象 - 让键 A 和键 B 共享同一个字符串对象,那么refcount+1
显然是第二种做法更省内存
共享对象机制对于节约内存非常有帮助, 数据库中保存的相同值对象越多, 对象共享机制就能节约越多的内存
Redis 只对包含整数值的字符串对象进行共享,并且范围是0~9999,创建共享字符串对象的数量可以通过修改 redis.h/REDIS_SHARED_INTEGERS
常量来修改
另外, 这些共享对象不单单只有字符串键可以使用,比如像list嵌套了这些整形字符串,同样可以共享