Q:使用对象的好处
- redis可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。
- 可以针对不同的使用场景,为对象实现多种数据结构。从而优化对象在不同场景下的使用效率。
redis使用引用技术,来判断判断该对象是否需要回收。 然后就是通过实现对象共享。
对象的种类
-
字符床对象
-
列表对象
-
哈希对象
-
集合对象
-
有序对象
创建键值对的时候,至少创建两个对象,一个是键对象,一个是值对象。都是字符串对象
typedef struct redisObject{
//类型
unsigned type:4;
//编码
unsigned encoding:4;
//指向底层实现数据结构的指针
void *ptr;
}robj;
每一个对象都是由一个redisobject结构表示的,三个属性,type属性 encoding属性 ptr属性
一个对象可以使用不同类型的属性。
1.字符串对象
字符串对象编码格式主要是有三种:
- 当字符串对象保存的是整数值时候,并且这个整数值可以使用long保存,那么直接将ptr指向该整数值。编码为int。
- 当字符串对象保存的是字符串时候,并且字符串大小大于39字节时候,使用SDS动态字符串实现,将ptr指向SDS。编码为raw。
- 当字符串对象保存的是字符串时候,并且字符串大小小于39字节时候,使用sdsdr实现,编码为embstr。
好处:
- embstr编码将创建字符串对象所需要的内存空间,从两次分配缩减为一次分配。
- 释放内存时候,也从两次释放缩减为一次释放
- 因为emstr编码的字符串对象的所有数据都保存在一块连续的内存中。更好的体现缓存带来的优势。
字符串对象是redis中五种类型中唯一种会被其他对象嵌套使用的对象。
2.列表对象
列表对象最主要有两种编码方法
- 压缩列表ziplist
- 双端列表linklist
编码转换条件:所有元素长度都要小于64字节 保存元素个数要小于512
上面两个条件有一个不符合都会从 ziplist转换为 linkedlist
3.哈希对象
哈希对象最主要有两种编码方法:
- hashtable字典
- ziplist压缩对象
(1)底层使用压缩列表实现
将要保存的键值对,创建两个字符串对象,一个是用来保存键值对的键,另外一个是用来保存键值对的值。然后依次压入队列尾部。保证键值对的对象是相互依靠的。键在前,值在后。
编码转换的条件:如果键值对的长度过长
如果键值对的值过于大
4.集合对象
集合对象最主要有两种编码方法:
- intset
- hashtable字典
1.intset的集合对象使用的是整数集合作为底层实现,集合所有元素都存储于此(如果使用的是intset则是有序的)
2.hashtable使用字典,字典的每一个键为一个字符串对象。后面都是接null
编码转换条件:存储的都是整数
存储的个数要小于512
5.有序集合对象(使用ziplist,跳表)
Q:判断该命令是否能作用于该对象(通过对象的type实现)
客户端发送消息
查询redisobject中的type对象
执行 返回错误信息
redis用C实现的,所以要自己实现垃圾回收功能,使用的是引用计数法。
- 在创建一个新对象时,引用计数的值会初始化为1
- 当对象被新的程序(新的客户端)引用时候,引用计数加一
- 当不在被一个引用计数引用时候,计数减一
- 当引用计数为0时,GC
对象共享
- 将数据库键值对的值指针指向一个现有的值对象。
- 将共享内存对象的引用计数加一
redis不共享包含字符串对象的对象
虽然共享对象可以节约空间,但是受到CPU影响,因为每一次判断都是需要花费一定量的时间
而且花费的时间是于对象复杂度成正比的。
redis只对包含整数值的字符串对象进行共享。