简单动态字符串

字符串

作为内存数据库,Redis对字符串的底层数据结构做了很多优化,通过了解Redis的数据结构,我对Redis的高性能有了更深的理解。

Redis中的字符串

Redis中的字符串有两种表现形式:

  • C语言传统字符串(以空字符结尾的字符数组) :适用于无需对字符串值进行修改的地方(eg:打印日志)
  • SDS: 可以被修改的字符串(eg:大部分场景)

SDS简介

class SDS {
    // SDS中已使用字节的数量 = SDS保存的字符串的长度
    int len;
    // 记录SDS中未使用字节的数量
    int free;
    // 保存的字符串
    char[] buf;
}
  • len:已使用空间大小(字符串的长度)
  • free: 未使用空间大小
  • buf: 字符串内容
    图示:在这里插入图片描述

SDS VS C

相比于C类字符串,SDS具有很多C字符串不具备的特点。

  • 获取字符串的长度

    C字符串: 由于没有记录自身的长度,所以要遍历整个字符串,O(n)
    SDS: 获取len属性O(1)

  • 杜绝缓冲区溢出

    C类字符串(会溢出)
    ①: s1 =“Redis”; s2=“MongoDB”;
    在这里插入图片描述
    ②:s1 =“Redis Cluster”;
    在这里插入图片描述
    ③:缓存区溢出,此时的s2由原来的MongoDB变成了Cluster,原因:s1没有预分配冗余空间

    SDS(不会溢出)
    ①:查看剩余空间(free)是否足够
    在这里插入图片描述

    ②:如果足够,则直接使用预分配的空间;如果不够,则先扩容(同时预分配冗余空间),再拼接。
    在这里插入图片描述

  • 减少字符串修改带来的内存重分配次数

    C字符串
    因为C字符串的长度和底层数组长度之前存在着关联性(底层数组长度=C字符串长度+1,额外的一空间用于保存空字符串),所以每次增长、缩短一个字符串,程序总要对这个字符串进行内存重分配操作;但是内存重分配涉及复杂的算法,并且可能需要执行系统调用,所以比较耗时。
    SDS (空间预分配+惰性释放)
    ①:空间预分配 (扩容策略)
    当SDS的剩余空间不足需要进行扩容时,不仅会分配扩容需要的必要空间,还会分配额外的未使用空间。
    额外分配的空间: 如果修改后,SDS的长度(len属性)< 1M,则分配和len一样大的额外空间(free =len),此时数组buf的实际长度为:2 X len + 1;
    ②:惰性空间释放 (缩容策略)
    当SDS需要缩容时,程序并不会立即回收多出来的空间,而是使用free属性将多余的空间记录下来,等待将来使用。
    在这里插入图片描述
    在这里插入图片描述

  • 二进制安全

    C字符串
    C字符串必须符合特定的编码(eg:ASCII),并且除了字符串末尾外,字符串里面不能包含空字符(否则最先读入的空字符会被认为是字符串结尾),这就限制C字符只能保存文本数据,不能保存图片、音频、视频、压缩文件等二进制数据。
    SDS
    SDS在处理二进制数据时,不是通过空字符来判断字符串是否结束,而是通过len属性。所以SDS不仅可以保存文本数据,还可以保存任意格式的二进制数据。

  • 兼容部分C字符串函数

    虽然SDS是二进制安全的,但是还是遵循了C字符以空字符结尾的习惯,这样就可以使用部分C函数,避免了重复开发。

总结

相比于C字符串,Redis的SDS具有以下的特点:

  • 常数级的获取字符串长度
  • 杜绝了缓冲区溢出
  • 减少了字符串修改带来的内存重分配次数(注意:不是避免)
  • 二进制安全(这就意味着我们可以将图片、视频等内容保存在Redis中,我们通常只用String保存字符串)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值