bigywater.tech
Redis · 16

大 Key 的内存占用

用MEMORY USAGE测5种大小的字符串和两种1000条目的集合类型,看大key的内存开销占比是怎么变化的,以及不同类型编码对内存占用的影响。

14.7%
100000字节value反常偏高的开销占比
6.4倍
同样1000条目,hash比list多占的内存
非单调
开销占比不是随value变大而一路下降

做的事:五种大小的字符串,测MEMORY USAGE

MEMORY USAGE命令能告诉你一个key在内存里到底占了多少字节,包括各种内部开销。

代码for n in [10, 100, 1000, 10000, 100000]: r.set(f"key_{n}", "x" * n) print(r.memory_usage(f"key_{n}"))

验证:开销比例不是恒定的,大key反而更吃亏

测出的5组数字,看额外开销占比的变化趋势。

结果value 10字节 → MEMORY USAGE 48字节 (开销38字节,380%) value 100字节 → MEMORY USAGE 138字节 (开销38字节,38%) value 1000字节 → MEMORY USAGE 1051字节 (开销51字节,5.1%) value 10000字节 → MEMORY USAGE 10268字节 (开销268字节,2.7%) value 100000字节→ MEMORY USAGE 114717字节 (开销14717字节,14.7%)

从10字节到10000字节,开销占比是一路下降的(固定的对象头开销被摊薄);但到100000字节这一档,开销占比又跳回了14.7%——比10000字节那一档反而更高。这说明value从10000字节涨到100000字节的过程中,跨过了内存分配器的某个尺寸台阶,触发了更粗粒度的内存块分配(比实际需要的字节数多分配了一截),这部分"多分配但没真正用上"的空间,也被算进了MEMORY USAGE里。

这是一个容易被忽视的点:"大key开销占比应该更低"这个直觉不总是对的——具体开销比例取决于内存分配器在哪个尺寸区间做怎样的对齐/分级策略,不是一条平滑下降的曲线。

验证:同样1000个"条目",不同类型的内存占用差很多

1000个字段的hash,跟1000个元素的list,同样量级的数据,占用差多少。

结果1000个字段的hash(每个字段"fN"→"vN") OBJECT ENCODING → hashtable MEMORY USAGE → :38060字节 1000个元素的list(每个元素"vN") OBJECT ENCODING → listpack MEMORY USAGE → :5928字节 比例:38060 / 5928 ≈ 6.4倍

差了6.4倍,原因有两层:第一,hash存的是"字段名+值"两份数据,list只存"值"一份,数据量本身就接近两倍;第二,也是更主要的原因,hash在1000个字段时已经超过默认阈值转成了 hashtable 编码(真正的哈希表,每个桶都有额外的指针开销),而list的1000个元素还没超过listpack阈值,依然是紧凑的连续内存结构。同样"1000个条目",编码是紧凑结构还是标准哈希表,带来的内存差异远比看起来的大。

分步演示:MEMORY USAGE揭示的内存开销规律

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

大key的内存开销占比不是单调下降的
这一步新验证的测试

    本文用到的工具

    • 本机 Redis 8.10.1 单节点
    • MEMORY USAGE:测量单个key的实际内存占用
    京ICP备2026067502号-1京公网安备11010502063487号