Redis淘汰key后内存未降是因分配器未归还内存给OS,导致used_memory_rss居高不下、mem_fragmentation_ratio>1.5;需通过activedefrag、重启或调整malloc策略缓解。

Redis 淘汰了大量 key 后内存没降,不是淘汰没生效,而是内存没真正归还给操作系统——这是 jemalloc(或 libc malloc)分配器的常见行为,和 Redis 自身逻辑无关。
为什么 INFO memory 显示已淘汰但 used_memory 不变
Redis 调用 free() 释放内存后,底层分配器通常不会立刻把内存还给 OS,而是保留在进程堆内供后续复用。这会导致:
-
used_memory(Redis 统计的已分配字节数)会下降,但下降幅度可能滞后或不明显 -
used_memory_rss(实际驻留内存)往往居高不下,甚至继续上涨 -
mem_fragmentation_ratio> 1.5 是典型信号,说明存在严重内存碎片
验证方式:redis-cli INFO memory | grep -E "(used_memory|used_memory_rss|mem_fragmentation_ratio)"。如果 used_memory_rss / used_memory > 2,基本可断定是分配器层的问题。
maxmemory-policy 配置正确但淘汰未触发的常见原因
淘汰策略只是“允许删”,不等于“自动删”。必须同时满足三个条件才会真正触发淘汰:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
maxmemory必须显式设置(默认为 0,即无限制),例如:CONFIG SET maxmemory 2gb -
maxmemory-policy不能是noeviction(默认值),否则写入直接报(error) OOM command not allowed when used memory > 'maxmemory' - 必须有**新写入请求**(如
SET、LPUSH)触发内存检查;纯DEL或过期 key 清理属于“被动回收”,不走淘汰策略路径
快速确认:执行 redis-cli CONFIG GET maxmemory 和 CONFIG GET maxmemory-policy,两个值都得是非默认且合理。
删除数据后 RSS 内存不释放的实操缓解方案
这不是 bug,但会影响监控和扩容判断。短期可用以下方法压低 used_memory_rss:
- 手动触发内存整理(仅限 jemalloc):
redis-cli CONFIG SET activedefrag yes,并确保active-defrag-threshold-lower和active-defrag-cycle-min已调高(默认太保守) - 重启实例(最彻底):适用于可接受短时中断的场景;注意提前
SAVE或确认启用了RDB/AOF - 避免小对象高频增删:比如用
HSET批量写入代替多次SET,减少碎片产生源头 - 换用
malloc编译 Redis(不推荐生产):启动时加make MALLOC=libc,libc 的malloc更倾向归还内存,但并发性能略低
注意:activedefrag 在 Redis 4.0+ 默认关闭,且对 CPU 有轻微占用,上线前需压测。
真正容易被忽略的是:淘汰策略只解决“写入不阻塞”,不解决“内存归还”。如果你依赖 used_memory_rss 做容量告警或自动扩缩容,必须把分配器行为纳入监控逻辑——比如同时看 mem_fragmentation_ratio 和 used_memory_peak,而不是只盯一个数字。

















