1、SDS的定义
len:buf数组中使用字节的数量
free:buff数组中未使用字节的数量
2、SDS与C字符串的区别
2.1 获取字符串长度的复杂度
C字符串不记录自身的长度信息,为了获取C字符串的长度,程序必须遍历整个字符串。
SDS在len属性中记录了SDS本身的长度。
Redis将获取字符串长度所需的时间复杂度降低到了O(1),确保了获取字符串长度的工作不会成为Redis的性能瓶颈。
2.2 杜绝缓冲区的溢出
C字符串不记录自身长度带来的一个问题是容易造成缓冲区溢出。比如strcat函数可以将src字符串中的内容拼接到dest字符串的末尾,假设用户在执行这个函数时已经为dest分配了足够的内存。可以容纳src字符串的所有内容,一旦这个假设不成立就会产生缓冲区溢出。
当SDS的API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求。如果不满足API会自动将SDS的空间扩展至所需的大小,然后才执行实际的修改操作。使用SDS既不需要手动修改SDS的空间大小,也不回出现缓冲区溢出问题。
2.3 减少修改字符串时带来的内存重分配次数
一个包含了N个字符的C字符串底层是一个N+1个字符长的数组,所以每次增长或者缩短C字符串,都要对这个C字符串的数组进行一次内存重分配操作。内存重分配设计复杂的算法,可能需要执行系统调用,通常是一个比较耗时的操作:
- Redis作为数据库,经常被用于速度要求严苛、数据被频繁访问的场合,导致修改频繁、内存重分配次数多、性能下降。
- 通过未使用空间,SDS实现了空间预分配和惰性空间释放两种优化策略。
2.4 二进制安全
C字符串的字符必须符合某种编码,除了字符串末尾之外不可以出现空字符,因此只能保存文本数据,而不能保存图片、音频、视频、压缩文件这样的二进制数据。
为了确保Redis可以适用各种不同的场景,SDS的API都是二进制安全的,以处理二进制的方式来处理SDS存放在buf数组里的数据。程序不会对其中的数据做任何限制、过滤、假设。数据写入时是什么样的,读出时就是什么样的。
2.5 兼容部分C字符串函数
3 总结
C字符串 | SDS | |
---|---|---|
获取字符串长度的时间复杂度 | O(N) | O(1) |
API安全 | 不安全,造成缓冲区溢出 | 是安全的,不会造成缓冲区溢出 |
修改字符串长度N次执行内存重分配的次数 | 需要执行N次 | 最多需要N次 |
文本数据 | 只能保存文本数据 | 可以保存文本数据或二进制数据 |
<string.h>库中的函数 | 可以使用 | 可以使用一部分 |
- Redis使用C字符串作为字面量,大多数情况下使用SDS作为字符串表示。