bigywater.tech
Redis · 14

Redis 对象共享整数

按文档描述的条件测试小整数共享池,用OBJECT REFCOUNT和10万key的内存对比两种独立证据,验证这个优化在本机的Redis版本里是否还在生效。

REFCOUNT=1
测出来的,不是预期的共享计数
368字节
10万key两种场景下几乎为0的内存差异
诚实的反直觉结论
没有观察到教科书描述的共享效果

做的事:按老版本Redis的说法,验证小整数共享池

Redis历史上有一个广为人知的优化:0~9999的小整数会被预先创建好,多个key指向同一个共享对象。

操作,按文档描述的生效条件CONFIG GET maxmemory → :0(满足共享条件) CONFIG GET maxmemory-policy → :noeviction(满足共享条件) SET z1 42 SET z2 42 OBJECT REFCOUNT z1

验证:REFCOUNT没有显示出共享的样子

如果真的共享,REFCOUNT应该是一个很大的数字(表示很多key在引用同一个对象)。

结果SET z1 42 SET z2 42 OBJECT ENCODING z1 → :int(满足能被共享的编码条件) OBJECT REFCOUNT z1 → :1 OBJECT REFCOUNT z2 → :1 DEBUG OBJECT z1 → refcount:1 encoding:int ...

不管用 OBJECT REFCOUNT 还是更底层的 DEBUG OBJECT,两个key(z1、z2)都各自显示引用计数为1,完全没有"共享同一个对象"该有的巨大计数。这跟很多资料里描述的老版本Redis行为对不上。

验证:换一种更直接的证据——用内存占用差异做独立验证

如果共享真的存在,10万个key全设成同一个小整数,应该比10万个各不相同的大整数省下大量内存。

结果10万个key全部SET成同一个可共享的小整数(42): DBSIZE → 100000 used_memory → :6362048 字节 10万个key各自SET成不重复的随机大整数(不可共享): DBSIZE → 100000 used_memory → :6362416 字节 两者只差368字节,几乎没有差别!

如果小整数对象真的被10万个key共享,"全部指向同一个42"的内存占用应该远小于"10万个各不相同的大数字"(前者理论上只需要一份对象+10万个指针,后者需要10万份完整对象)。测出来的结果是:两者几乎一模一样——这从内存证据的角度,独立确认了 OBJECT REFCOUNT 显示的现象:这个的Redis 8.10.1实例里,小整数共享池没有观察到在生效。

这是一个诚实的"反直觉"结论:很多文章和书籍里描述的"Redis会共享0~9999的整数对象",在本文测试的这个环境和版本下并没有被观察到——具体原因可能是版本演进中这个特性被调整过、或者需要额外未知的开启条件,这一点本文没有找到确凿的源码级证据,只能如实报告观察到的现象:不要凭旧资料假设这个优化一定在生效,需要的话应该像本文这样自己动手验证一次。

分步演示:验证一个"广为人知"的优化到底还在不在

每一步都是本文上面用redis-cli和Python脚本跑出来的原始结果。

两种独立的证据,都没有观察到小整数共享效果
这一步新验证的证据

    本文用到的工具

    • 本机 Redis 8.10.1 单节点
    • OBJECT REFCOUNT / DEBUG OBJECT:检查引用计数
    • Python redis-py pipeline:批量写入10万个key做内存对比
    京ICP备2026067502号-1京公网安备11010502063487号