• 【Redis】对象


    目录

    对象

    对象的类型与编码

    类型

    编码和底层实现

    字符串对象

    编码的转换

    列表对象

    哈希对象

    集合对象

    有序集合对象

    类型检查与命令多态

    类型检查的实现

    多态命令的实现

    内存回收

    对象共享

    对象的空转时长


    对象

    对象的类型与编码

    当我们在Redis的数据库中新创建一个键值对时,我们至少会创建两个对象,一个对象用作键值对的键,另一个对象用作键值对的值。

     

    类型

    type属性记录了对象的类型

     

    编码和底层实现

    对象的ptr指针指向对象的底层实现数据结构

    encoding属性记录了对象所使用的编码

     

    字符串对象

    字符串对象的编码可以是int、raw、embstr

    字符串值大于39字节,编码为raw

    字符串值小于等于39字节,编码为embstr

    区别:raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则会通过调用一次内存分配函数来分配一块连续的空间,空间中依次包含redisObject和sdshdr两个结构

    embstr编码的字符串对象来保存短字符串值有以下好处:

    1. Embstr编码将创建字符串对象所需的内存分配次数从2次降为1次
    2. 释放embstr编码的字符串对象只需要调用一次内存释放函数,而释放raw编码的字符串对象需要调用两次内存释放函数
    3. 因为embstr编码的字符串对象的所有数据都保存在一块连续的内存里,所以这种编码的字符串对象比起raw编码的字符串对象能够更好的利用缓存带来的优势

    Long double类型表示的浮点数在Redis中也是作为字符串值来保存的

     

    编码的转换

    当我们对象中保存的不再是整数值,而是一个字符串值,那么字符串对象的编码将从int变为raw

    embstr编码的字符串对象实际上是只读的,当我们对embstr编码的字符串对象执行任何修改命令时,程序会先将对象的编码从embstr转为raw,然后再执行修改命令,因此,一个embstr编码的字符串再修改后,就会变成一个raw编码的字符串对象。

    列表对象

    列表对象的编码可以是ziplist或者linkedlist

    ziplist

     

    linkedlist

     

    linkedlist编码的列表对象使用双端链表作为底层实现,每个双端链表节点(node)都保存了一个字符串对象,而每个字符串对象都保存了一个列表元素

    字符串对象是Redis五种类型的对象中唯一一种会被其它四种对象嵌套的对象

    编码转换

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

    不能满足这个两个条件的列表对象需要使用linkedlist编码

    哈希对象

    哈希对象的编码可以是ziplist或者hashtable

    ziplist

    1. 保存了同一键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在后
    2. 先添加到哈希对象中的键值对会被放在压缩列表的表头方向,而后添加到哈希对象中的键值对会被放在压缩列表的表尾方向

     

     

    hashtable

    hashtable编码的哈希对象使用字典作为底层实现,哈希对象中的每个键值对都使用一个字典键值对来保存:

    1. 字典的每个键都是一个字符串对象,对象中保存了键值对的键
    2. 字典的每个值都是一个字符串对象,对象中保存了键值对的值

     

    编码转换

    当哈希对象同时满足以下两个条件时,哈希对象使用ziplist编码:

    1. 哈希对象保存的所有键值对的键和值的字符串长度都小于64字节
    2. 哈希对象保存的键值对数量xiaoyu512个

    不能满足这两个条件的哈希对象需要使用hashtable编码

    集合对象

    集合对象的编码可以是intset或者hashtable

    Intset

     

    Hashtable

    hashtable编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串对象包含了一个集合元素,而字典的值则全部被设置为NULL

     

    编码转换

    当集合对象可以同时满足以下两个条件时,对象使用intset编码:

    1. 集合对象保存的所有元素都是整数值
    2. 集合对象保存的元素数量不超过512个

    不能满足这两个条件的集合对象需要使用hashtable编码

    有序集合对象

    有序集合的编码可以是ziplist或者skiplist

    Ziplist

    Ziplist编码的有序集合对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),而第二个元素则保存元素的分值(score)

     压缩列表内的集合元素按分值从小到大进行排序,分支较小的元素被放置在靠近表头的位置,而分值较大的元素被放置在靠近表尾的位置

     

    Skiplist

     

    有序集合为什么需要同时使用跳跃表和字典来实现?

    同时使用字典和跳跃表的性能会更高。如果只使用字典来实现有序集合,那么虽然以O(1)复杂度查找成员的分值这一特性会被保留,但因为字典以无序的方式来保存集合元素,所以每次在执行范围操作时,程序都需要对字典保存的所有元素进行排序,完成这种排序至少O(NlogN)时间复杂度,以及额外的O(N)内存空间。

     另一方面,如果只是用跳跃表来实现有序集合,那么跳跃表执行范围型操作的所有优点都会被保留,但没有了字典,所以根据成员查找分值这一操作的复杂度将从O(1)上升为O(logN)。

    编码转换

    当有序集合对象可以同时满足以下两个条件时,对象使用ziplist编码:

    1. 有序集合保存的元素数量小于128个
    2. 有序集合保存的所有元素成员的长度都小于64字节

    不能满足以上两个条件的有序集合对象将使用skiplist编码

    类型检查与命令多态

    类型检查的实现

     

    多态命令的实现

    我们可以将DEL、EXPIRE、TYPE等命令也成为多态命令,因为无论输入键是什么类型,这些命令都可以正确运行。

    DEL、EXPIRE等命令与LLEN等命令的区别在于,前者是基于类型的多态——一个命令可以同时用于处理多种不同类型的键,而后者是基于编码的多态——一个命令可以同时用于处理多种不同编码。

     

    内存回收

    Redis在自己对象系统中构建了一个引用计数技术实现的内存回收机制

    1. 再创建一个新对象时,引用计数的值会被初始化为1
    2. 当对象被一个新程序使用时,它的引用计数值会被增一
    3. 当对象不再被一个程序使用时,它的引用计数值会被减一
    4. 当对象的引用计数值变为0时,对象所占用的内存会被释放

    对象共享

    多个键共享同一个值对象需要执行以下两个步骤:

    1. 将数据库键的值指针指向一个现有的值对象
    2. 将被共享的值对象的引用计数增一

     

    Redis会在初始化服务器时,创建一万个字符串对象,这些对象包含了从0到9999的所有整数值,当服务器需要用到值为0到9999的字符串对象时,服务器就会使用这些共享对象,而不是新对象。

    为什么Redis不共享包含字符串的对象?

      字符串对象值相对更加复杂,而一个共享对象保存的值越复杂,验证共享对象和目标对象是否相同所需的复杂度就会越高,消耗的CPU时间也会越多,因此,尽管共享更复杂的对象可以节约更多的内存,但受到CPU时间的限制,Redis只对包含整数值的字符串对象进行共享。

    对象的空转时长

     

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

    空转时长=当前时间-lru

    注意:

    如果服务器打开了maxmemory选项,并且服务器用于回收内存的算法为volatile-lru或者allkeys-lru,那么当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时长较高的那部分键会优先被服务器释放,从而回收内存。

  • 相关阅读:
    Navicat设置数据库权限
    【附源码】Python计算机毕业设计网上宠物商店系统
    Windows C++ VS2022 OpenVINO 物体检测 Demo
    这种动态规划你见过吗——状态机动态规划之股票问题(中)
    一些常见的必须会的谭浩强基本代码大全也是常考的应试是没问题的
    java面试题续集(二)
    星宿UI V2.1 开源wordpress资源下载小程序,流量主激励视频广告
    linux文件存储之inode,硬链接,软链接详解
    面试官:Kafka是什么,它有什么特性与使用场景?
    MySQL—约束—演示(基础)
  • 原文地址:https://blog.csdn.net/weixin_45912201/article/details/126244747