memory usage返回redis运行时真实分配的内存总量,包含键名、值数据、redisobject元数据、过期dictentry、底层容器开销及内存对齐填充等;它比--bigkeys更准因基于jemalloc实际分配量,但会重复计算共享对象、不区分是否已过期,且对大结构有阻塞风险。

MEMORY USAGE 返回的不是“数据大小”,而是 Redis 运行时真实分配的内存总量,包含编码开销、指针、哈希表扩容冗余、过期字段等——直接拿它当 value 字节数用,会严重误判容量。
为什么 MEMORY USAGE 比 --bigkeys 准,但又不能直接信
--bigkeys 只做粗略采样:对 HASH 默认只查 100 个 field,再按平均长度×总字段数估算;它完全忽略 dict 扩容后空桶占用、entry 结构体、redisObject 元数据。而 MEMORY USAGE 是 jemalloc 实际返回的分配字节数,含全部运行时开销。
但这也正是陷阱所在:
- 一个存了 10 万字段的
HASH,--bigkeys可能报 “~2MB”,MEMORY USAGE实测却达8–12MB(因扩容到 262144 桶,每个桶 + entry 至少 32 字节) - 已过期但尚未被惰性删除的 key,
MEMORY USAGE仍返回完整值(含redisObject.lru8 字节 + 过期字典中dictEntry额外 32–48 字节) - 字符串对象若被多处引用(
refcount > 1),MEMORY USAGE不体现共享,重复计算
MEMORY USAGE 命令执行前必须确认的三件事
这个命令在高并发或大结构上可能阻塞主线程——Redis 7 虽优化了部分遍历逻辑,但对 LIST/SET/HASH 类型仍需逐节点访问。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 确认目标 key 存在且类型明确:
MEMORY USAGE对不存在的 key 返回0,容易误判为“空”而非“不存在” - 避开生产高峰批量调用:一次查 100 个可疑 key,可能触发
SLOWLOG GET中的 latency spikes - 检查
client-output-buffer-limit normal配置:若设得太小(如1mb 512kb 60),大结果会直接断连,返回Connection reset by peer
MEMORY USAGE 的典型误用场景与参数应对
很多人改用 ziplist 编码的 HASH 后发现 MEMORY USAGE 反而变大——这不是 bug,是编码切换阈值和内存对齐导致的。
- ziplist 启用条件严格:
hash-max-ziplist-entries(默认 512)且所有value≤hash-max-ziplist-value(默认 64 字节);超限立刻转 dict,内存占用跳变明显 - jemalloc 分配有粒度:一个 65 字节的字符串实际占 80 字节,
MEMORY USAGE返回的就是这 80,不是 65 -
SAMPLES参数仅对集合类有效(SET/ZSET/HASH),用于控制采样元素数量,默认 5;对STRING或LIST无效,传了也忽略
真正要盯住的不是单 key,而是 MEMORY STATS 里的关键字段
单 key 再准,也掩盖不了整体内存健康问题。你真正该定期看的是:
-
overhead.total:元数据开销总和,若长期 >dataset.bytes的 30%,说明 key 过碎(比如百万个 1KB key,比一个 1GB key 更伤) -
fragmentation:碎片率 > 1.5 就得警惕,结合used_memory_rss / used_memory看是否真碎片,还是只是 jemalloc 缓存未归还 -
db.0.overhead.hashtable.expires:过期 key 占用的哈希表空间,如果远高于keys.count,说明大量 key 已过期但没被清理
这些字段才是容量规划和淘汰策略调整的依据,而不是盯着某个 MEMORY USAGE 数值反复纠结。










