Redis使用SDS的原因

Redis使用SDS(Simple Dynamic String)代替C字符串,因为它提供常数复杂度获取长度、防止缓冲区溢出、减少内存重分配次数以及支持二进制安全性。SDS通过len属性实现O(1)获取长度,通过记录free空间实现空间预分配和惰性释放策略,从而提高性能和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • SDS定义
struct  sdsher{
//记录buf中已保存字符的长度
//等于SDS所保存的字符串的长度
int  len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
};

说明:SDS为了能够使用部分C字符串函数,遵循了C字符串以空字符结尾的惯例,保存空字符的1字节不计算在SDSlen属性中,并且为空字符分配额外的1字节空间,以及添加空字符到字符串末尾等操作,都是由SDS函数自动完成的,可以说空字符对使用者是不可见的

  • 为什么使用SDS(simple dynamic string)
    举个简单例子:一个简单的C字符串 “Redis”
    在这里插入图片描述
    C语言使用这种简单的字符串表示方法,并不能满足Redis对字符串在安全性、效率性以及功能方面的要求。

**

1、常数复杂度获取字符串长度

**
C语言中实现字符串长度计数的复杂度为O(N)。
而反观SDS中,因为其结构中保存了len这一属性,所以获取SDS长度的复杂度仅为O(1)。
并且我们不需要手动修改len属性,设置和更新SDS长度的工作是由SDS的API在执行时自动完成的。

2、杜绝缓冲区溢出

C语言由于不记录自身长度,所以又带来一个问题:容易造成缓冲区溢出(buffer overflow)。
举个栗子!当我们拥有两个C字符串s1,s2。而恰好s1、s2的内存是紧挨着的,那么当对s1执行某些操作,例

### Redis 的简单动态字符串 (SDS) 实现与使用 #### 1. SDS 结构定义 Redis 中的简单动态字符串(Simple Dynamic String, SDS)是一种自定义的字符串表示方式,其核心目的是优化 C 字符串的功能不足之处。SDS 是通过 `struct sdshdr` 定义的一个结构体来实现的[^1]: ```c typedef char *sds; struct sdshdr { int len; // 记录当前已使用的字节数 int alloc; // 记录当前分配的总字节数 unsigned char flags; // 存储一些标志位信息 char buf[]; // 可变长度字符数组,存储实际的字符串内容 }; ``` 其中: - **len** 表示当前缓冲区中已经保存的有效字符数量。 - **alloc** 表示当前缓冲区总共可以容纳多少个字符。 - **buf** 是一个可变长度的字符数组,用来存储具体的字符串内容。 这种设计使得 SDS 能够高效地处理字符串操作,而不需要像传统 C 字符串那样频繁进行内存重分配[^3]。 --- #### 2. SDS 和 C 字符串的区别 相比于传统的 C 字符串,SDS 提供了更多的功能和更高的效率。以下是两者的主要区别[^2]: | 特性 | C 字符串 | SDS | |-------------------------|-----------------------------------|--------------------------------------| | 长度获取 | 需要遍历整个字符串直到遇到 `\0` | 直接读取 `len` 成员变量 | | 修改安全性 | 易受缓冲区溢出攻击 | 自动调整空间大小,防止溢出 | | 性能 | 操作复杂度较高 | 更高效的内存管理机制 | 由于这些特性,SDSRedis 这样的高性能场景下表现得更加出色。 --- #### 3. SDS 的主要优势 为了满足 Redis 对性能的要求,SDS 设计了许多独特的特点[^3]: - **预分配冗余空间**: 当向 SDS 添加新数据时,会预先分配额外的空间给未来可能的增长预留位置。这减少了连续多次追加操作所需的内存重新分配次数。 - **惰性收缩策略**: 删除部分数据时不立即释放多余的空间,而是保留下来以便后续再次利用。这样既提高了删除操作的速度又降低了因频繁调用 malloc/free 带来的开销。 - **二进制安全**: 不仅支持普通的 ASCII 文本,还可以很好地处理任意形式的二进制数据序列。 --- #### 4. 使用方法举例 下面展示如何创建、修改以及销毁一个简单的 SDS 字符串实例: ```c #include "sds.h" int main() { sds str = sdsnew("hello"); // 创建一个新的 SDS 字符串 "hello" printf("%s\n", str); // 输出原始字符串 str = sdscat(str, " world!"); // 将另一个子串附加到现有字符串后面 // 此处不会触发新的内存申请因为有足够剩余容量 printf("%s\n", str); // 打印最终结果 "hello world!" free(str); // 销毁并释放关联资源 } ``` 以上代码片段展示了基本的 SDS API 应用流程,包括初始化、拼接扩展以及其他常见操作。 --- #### 5. 关键函数说明 这里列举几个常用的 SDS 函数及其作用: - `sdsnew(const char *init)` : 根据指定初始值生成一个新的 SDS 对象; - `sdscat(sds s, const char *t)` : 把 t 后续连接至 s 上面形成更长的整体; - `sdsfree(sds s)` : 清理掉某个特定 SDS 占用的所有内部存储区域; 每项都经过精心设计从而达到最佳运行效果的同时兼顾易用性和灵活性需求。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值