redis数据结构(六):针对用户的数据结构对象

字符串对象 string

三种编码

  • int
  • embstr
  • raw

int

如果一个字符串对象保存的是整数,并且这个整数值可以用long来表示,那么这和字符串会将整数保存在ptr中,将void* 转换成long


int.png

raw

如果字符串的长度大于39字节,那么用SDS来保存这个字符串,编码为raw(这是最正常的情况)


raw.png

embtr

如果这个字符串的大小,小于等于39,那么编码为embter,存储方式还是SDS。但这个SDS和raw有所区别。

embstr和raw都是用一个robj和shshdr来存储字符串的。raw会调用两次内存分配,分别创建两块内存,分别给robj和shshdr。embter只会调用一次内存分配,只创建一块内存,robj和shshdr呢诶村地址紧挨着共用该内存。

这样做的好处

  • 内存分配从两次变为一次
  • 释放内存从两次变为一次
  • 节约内存

编码转换

int和embtr都是有条件的嘛,当不满足这个条件了,就都会变成raw格式了。
比如:
int类型后面调用函数追加了字符串
embtr类型追加字符串后长度大于39

列表对象 list

三种编码 (三种内部数据结构)

  • ziplist
  • linkedlist
  • quicklist

列表是什么

列表就是传统意义上的队列。只能对队列头和尾进行入队和出队的操作。中间不可以操作。

3.2之前的版本

3.2之前的版本没有quicklist底层数据结构

  1. 保存的所有字符串长度都小于64字节
  2. 元素数量小于512个

二者都满足,使用ziplist
任一不满足,使用linkedlist

3.2及以后的版本

统一使用quicklist

哈希对象 hash

两种编码(底层数据结构)

  • ziplist
  • hashtable

ziplist

压缩列表怎么存呢??
答案是:列表中,前面是key,后面是value,紧挨着。


压缩列表存hash.png

hashtable

传统意义的数组+链表的形式。

编码转换

  1. 保存的所有字符串长度都小于64字节
  2. 元素数量小于512个

二者都满足,使用ziplist
任一不满足,使用hashtable

集合对象 set

两种编码方式(内部数据结构)

  • intset
  • hashtable

intset

整数的set,就直接用intset来存储。

hashtable

hashtable是key/value的形式,怎么存set呢。只用key,value值不用全为null就好了。还是使用链表法解决冲突。

有序集合

两种编码方式(内部数据结构)

  • ziplist
  • skiplist

ziplist

还是key/value内存地址紧挨着。有序集合需要从小到大排序。分值较小的靠近表头,分值较大的靠近表尾。


压缩列表存有序集合.png

skiplist

使用跳表和字典来实现

编码转换

  1. 保存的所有字符串长度都小于64字节
  2. 元素数量小于128个

二者都满足,使用ziplist
任一不满足,使用skiplist

对象共享

假设a创建了一个包含整数值100的字符串作为值,如果这时b也创建一个包含整数值100的字符串。那么服务器有以下两种做法:

  1. 为键b新创建一个包含整数值100的字符串对象
  2. 让键a键b共享一个对象

很明显,第二种取胜,更节约内存。

redis让多个指针指向同一个对象分两步:

  1. 将数据库key的指针,指向同一个对象
  2. 将被共享的值对象的引用计数 +1
对象共享.png

如图所示,a的引用计数为7,set b后引用计数变为8。当b修改了之后,a的计数重新变为7。b与其他键共用了101值对象,所以引用计数是2。

redis会共享0-9999的字符串对象。

对象的空转时长

空转时长.png

该属性记录了对象最后一次被命令程序访问的时间。

执行object idletime,使用当前时间 减去 空转时间lru得到的空转时长。

内存回收的策略,也会根据这个最后访问时间去进行决策。

内存回收策略,在redis存储章节展开讲。

你可能感兴趣的:(redis数据结构(六):针对用户的数据结构对象)