对象
Redis真正实现的是对象,是基于前面至少一种数据结构
一般会有键和值两个对象用redisObject表示
使用TYPE命令时返回的是键对应的值对象类型
使用OBJECT ENCODING命令返回键对应的值对象的编码
encoding属性极大提高了效率,不同场景下用不同编码
字符串对象
编码可以是int、raw(SDS)、embstr(SDS)
如果保存的字符串对象值长度小于等于44字节,会用embstr(针对短字符串有优化)
raw会调用两次内存分配来形成redisObject和sdshdr,释放需两次
embstr只需调用一次,释放也只需一次
long double类型也会用字符串来保存,执行操作才会转换成浮点型,然后把结果转换成字符串保存
编码转换
int类型的数据经过APPEND命令加入字符串,会转成raw
embstr是只读的,经过修改命令后会变更成raw编码
列表对象
可以是ziplist和linkedlist
//////////////////////////////////////////
满足以下两个条件会用ziplist编码:
- 所有字符串元素长度都小于64字节
- 元素数量小于512个
哈希对象
可以是ziplist或者hashtable
满足一下条件会使用ziplist
-
键和值的字符串长度都小于64字节
-
键值对数量小于512
集合对象
intset或者hashtable
满足以下两个条件,会使用intset编码
-
所有元素都是整数值
-
元素数量不超过512个
有序集合对象
可以是ziplist或者skiplist skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃跳跃表
满足以下条件,会使用ziplist编码
-
元素数量小于128个
-
所有元素长度小于64字节
类型检查与命令多态
执行命令前,通过检查type属性来判断是否执行
然后检查encoding来确定具体用哪个对应的API来执行
内存回收
引用计数(跟jvm垃圾回收类似)
创建新对象时,引用计数值初始化为1
随着被程序引用和完成,计数增减,到0后对象内存会被释放
对象共享
和上面的内存回收搭配使用,
在初始化服务器时,会创建0-9999所有整数值的一万个字符串对象
当服务器需要这些字符串对象时,会直接引用,计数+1,而不会新建
由于验证复杂的对象耗cpu,所以redis只对整数值的字符串对象进行共享
对象空转时长
redisObject中有个lru属性记录了对象最后一次被访问的时间
由命令OBJECT IDLETIME命令返回,他会访问对象,但不会修改对象lru属性
如果内存超过maxmemory上限,会优先释放lru属性大的对象
总结
-
Redis数据库中的每个键值对的键和值都是一个对象。
-
Redis共有字符串、列表、哈希、集合、有序集合五种类型的对象,每种类型的对象至少都有两种或以上的编码方式,不同的编码可以在不同的使用场景上优化对象的使用效率
字符串对象的编码可以是int(保存的整数值),raw(长字节),embstr(短字节)
列表对象的编码可以是压缩列表(短字节),双端列表(长字节)
哈希对象--->编码-->压缩列表,字典
集合对象--->编码-->整数集合,字典
有序集对象-->编码-->跳跃表, 压缩表
-
服务器在执行某些命令之前,会先检查给定键类型判断能否执行指定的命令,检查的是 "值对象"的类型
-
Redis对象系统使用引用计数实现内存回收机制,引用计数还可以对象共享,初始时,服务器程序+键A==2个引用。
-
Redis会共享值为0到9999的字符串对象。只对包含整数值的字符串对象进行共享
-
对象会记录自己的最后一次被访问的时间,这个时间用于计算对象的空转时间。服务器决定是否回收内存。