You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redis字符串缩短后,何时回收多余内存?

Redis字符串缩短后的内存回收时机

比如,当一个30M的字符串被修剪到只剩3字节时,Redis会在什么时候释放那些闲置的内存?留着大量未使用的空间显然会造成资源浪费。

Redis字符串(SDS)结构

Redis的字符串采用简单动态字符串(SDS)实现,64位版本的结构如下:

struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* 已使用字节数 */
    uint64_t alloc; /* 已分配字节数(不包含头部和终止符) */
    unsigned char flags; /* 低3位表示类型,高5位未使用 */
    char buf[]; /* 字符串内容缓冲区 */
};

sdstrim的实现(无内存回收逻辑)

以下是字符串修剪函数sdstrim的代码,它只负责修剪字符串内容,没有回收闲置内存的逻辑:

/* 移除字符串首尾连续出现的、属于cset(以null结尾的C字符串)的字符
 *
 * 调用后,原sds字符串不再有效,所有引用必须替换为调用返回的新指针。
 *
 * 示例:
 *
 * s = sdsnew("AA...AA.a.aa.aHelloWorld     :::");
 * s = sdstrim(s,"Aa. :");
 * printf("%s\n", s);
 *
 * 输出结果为 "HelloWorld"。
 */
sds sdstrim(sds s, const char *cset) {
    char *end, *sp, *ep;
    size_t len;

    sp = s;
    ep = end = s+sdslen(s)-1;
    while(sp <= end && strchr(cset, *sp)) sp++;
    while(ep > sp && strchr(cset, *ep)) ep--;
    len = (ep-sp)+1;
    if (s != sp) memmove(s, sp, len);
    s[len] = '\0';
    sdssetlen(s,len);
    return s;
}

内存回收的触发时机

从sdstrim的代码能看到,它仅更新了SDS的len字段(标记实际使用长度),但并没有调整alloc字段或释放多余的内存——这是Redis惰性内存回收策略的体现,具体回收时机分为三种:

  • 主动调用收缩API:需要显式调用sdsshrinktofit函数(对应Redis命令层面可以通过重新执行SET赋值,或使用MEMORY PURGE辅助),该函数会将SDS的内存分配缩小到实际使用的大小,直接释放闲置空间。比如在sdstrim执行后调用sdsshrinktofit(s),就能立刻回收30M到3字节之间的闲置内存。
  • 后续写操作触发扩容或覆盖:如果后续对该字符串执行追加、修改等操作,当需要的内存超过当前alloc时,Redis会重新分配新的内存块,旧的闲置内存会被内存分配器回收;但如果只是小范围修改,仍然会保留原有大内存块。
  • 键被清理:当该字符串键被DEL命令删除、过期自动清理,或者触发内存淘汰策略被移除时,整个SDS的内存会被Redis的内存分配器完整回收。

Redis的这种设计是为了平衡性能与内存利用率——保留闲置内存可以避免频繁内存分配/释放带来的系统开销,适合字符串可能再次扩容的场景;但如果确定不会再用到闲置空间,主动调用收缩操作就能避免资源浪费。

内容的提问来源于stack exchange,提问作者Name Null

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:35:20