动态字符串

Redis中的默认字符串表示方式是SDS,它不同于C语言的字符串。SDS具有len字段记录字符串长度,提供O(1)的时间复杂度获取长度。在拼接字符串时,SDS会检查内存空间,避免缓冲区溢出。此外,SDS还实现了空间预分配和惰性空间释放策略,以减少内存重分配,并且是二进制安全的,部分兼容C字符串函数。
摘要由CSDN通过智能技术生成

动态字符串

构造

redis使用SDS作为默认的字符串表示。

struct sdshdr {
    
    // buf 中已占用空间的长度
    int len;

    // buf 中剩余可用空间的长度
    int free;

    // 数据空间
    char buf[];
};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmCspG0t-1622432700875)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210531105319260.png)]

len表示字符串的长度。

free表示剩余空间的大小。

buf表示数据的空间。

SDS与C字符串的区别

  • len不包括最后的’\0’。C语言中的字符数组来表示长度N的字符串,字符数组最后一个元素总是为’\0‘。
  • strlen函数调用是直接调用的len字段的大小,所以时间复杂度为O(1),而C语言字符串是要遍历数组,直到遇到字符串结尾的空字符,时间复杂度为O(n)。
  • 使用C语言中的strcat函数时,如果未分配足够的内存空间,就可能会发生缓冲区溢出。redis中使用sdscat去拼接。
sds sdscat(sds s, const char *t) {
    return sdscatlen(s, t, strlen(t));
}
/*
 * 将长度为 len 的字符串 t 追加到 sds 的字符串末尾
 *
 * 返回值
 *  sds :追加成功返回新 sds ,失败返回 NULL
 *
 * 复杂度
 *  T = O(N)
 */
sds sdscatlen(sds s, const void *t, size_t len) {
    
    struct sdshdr *sh;
    
    // 原有字符串长度
    size_t curlen = sdslen(s);

    // 扩展 sds 空间
    // T = O(N)
    s = sdsMakeRoomFor(s,len);

    // 内存不足?直接返回
    if (s == NULL) return NULL;

    // 复制 t 中的内容到字符串后部
    // T = O(N)
    sh = (void*) (s-(sizeof(struct sdshdr)));
    memcpy(s+curlen, t, len);

    // 更新属性
    sh->len = curlen+len;
    sh->free = sh->free-len;

    // 添加新结尾符号
    s[curlen+len] = '\0';

    // 返回新 sds
    return s;
}

该函数会对空间进行判断,若内存不足则会返回null,否则就会对字符串进行拼接。

  • C语言中每次都会将字符串最后一个作为’\0‘,会有进行内存重新分配操作,如果在进行拼接和截断操作时,没有对内存进行操作,可能会发生缓冲区溢出和内存泄漏。redis的数据需要被频繁修改,所以需要减少内存重新分配。

    • 空间预分配:如果sds的长度小于1MB,程序会分配和len属性同样大小的未使用空间,即free空间。若大于1MB,则会分配1MB的未使用空间。扩展的时候,如果未使用空间足够,则会使用为使用空间,不需要进行内存重分配。
    • 惰性空间释放:sds需要缩短sds保存的字符串时,不会立即使用内存重分配,但是会用free记录下来,也就是会作为未使用空间进行保留下来。
  • 二进制安全。

  • 兼容部分C字符串函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值