对象共享
---------------
除了用于实现引用计数内存回收机制之外,
对象的引用计数属性还带有对象共享的作用。
举个例子,
假设键 A 创建了一个包含整数值 ``100`` 的字符串对象作为值对象,
如图 8-20 所示。
.. graphviz::
digraph {
label = "\n 图 8-20 未被共享的字符串对象";
rankdir = LR;
key_a [label = "键 A", shape = box, width = 1.5];
redisObject [label = "
redisObject | type \n REDIS_STRING | encoding \n REDIS_ENCODING_INT | ptr | refcount \n 1 | ... ", shape = record];
node [shape = plaintext];
number [label = "100"]
redisObject:ptr -> number;
key_a -> redisObject:head;
}
如果这时键 B 也要创建一个同样保存了整数值 ``100`` 的字符串对象作为值对象,
那么服务器有以下两种做法:
1. 为键 B 新创建一个包含整数值 ``100`` 的字符串对象;
2. 让键 A 和键 B 共享同一个字符串对象;
以上两种方法很明显是第二种方法更节约内存。
在 Redis 中,
让多个键共享同一个值对象需要执行以下两个步骤:
1. 将数据库键的值指针指向一个现有的值对象;
2. 将被共享的值对象的引用计数增一。
举个例子,
图 8-21 就展示了包含整数值 ``100`` 的字符串对象同时被键 A 和键 B 共享之后的样子,
可以看到,
除了对象的引用计数从之前的 ``1`` 变成了 ``2`` 之外,
其他属性都没有变化。
.. graphviz::
digraph {
label = "\n 图 8-21 被共享的字符串对象";
rankdir = LR;
key_a [label = "键 A", shape = box, width = 1.5];
key_b [label = "键 B", shape = box, width = 1.5];
redisObject [label = " redisObject | type \n REDIS_STRING | encoding \n REDIS_ENCODING_INT | ptr | refcount \n 2 | ... ", shape = record];
node [shape = plaintext];
number [label = "100"]
redisObject:ptr -> number;
key_a -> redisObject:head;
key_b -> redisObject:head;
}
共享对象机制对于节约内存非常有帮助,
数据库中保存的相同值对象越多,
对象共享机制就能节约越多的内存。
比如说,
假设数据库中保存了整数值 ``100`` 的键不只有键 A 和键 B 两个,
而是有一百个,
那么服务器只需要用一个字符串对象的内存就可以保存原本需要使用一百个字符串对象的内存才能保存的数据。
目前来说,
Redis 会在初始化服务器时,
创建一万个字符串对象,
这些对象包含了从 ``0`` 到 ``9999`` 的所有整数值,
当服务器需要用到值为 ``0`` 到 ``9999`` 的字符串对象时,
服务器就会使用这些共享对象,
而不是新创建对象。
.. topic:: 注意
创建共享字符串对象的数量可以通过修改 ``redis.h/REDIS_SHARED_INTEGERS`` 常量来修改。
举个例子,
如果我们创建一个值为 ``100`` 的键 ``A`` ,
并使用 :ref:`OBJECT REFCOUNT