Redis 对象共享

世界以痛吻我,我仍报之以歌。

简介

除了用于实现引用计数内存回收机制之外,对象的引用计数属性还带有对象共享的作用。

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

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

Redis 初始化

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

创建共享字符串对象的数量可以通过修改 redis.h/REDIS_SHARED_INTEGERS 常量来修改。

共享对象应用场景

这些共享对象不单单只有字符串键可以使用,那些在数据结构中嵌套了字符串对象的对象(linkedlist 编码的列表对象、hashtable 编码的哈希对象、hashtable 编码的集合对象,以及 zset 编码的有序集合对象)都可以使用这些共享对象。

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

当服务器考虑将一个共享对象设置为键的值对象时,程序需要先检查给定的共享对象和键想创建的目标对象是否完全相同,只有在共享对象和目标对象完全相同的情况下,程序才会将共享对象用作键的值对象,而一个共享对象保存的值越复杂,验证共享对象和目标对象是否相同所需的复杂度就会越高,消耗的 CPU 时间也会越多:

  • 如果共享对象是保存整数值的字符串对象,那么验证操作的复杂度为O(1)

  • 如果共享对象是保存字符串值的字符串对象,那么验证操作的复杂度为O(N)

  • 如果共享对象是包含了多个值(或者对象的)对象,比如列表对象或者哈希对象,那么验证操作的复杂度将会是O(N 2)

因此,尽管共享更复杂的对象可以节约更多的内存,但受到CPU时间的限制,Redis 只对包含整数值的字符串对象进行共享。