redis源码分析之简单动态字符串sds
2013-05-07 22:07
751 查看
Sds(Simple Dynamic String.简单动态字符串)是Redis底层所使用的字符串,它被用在几乎所有的redis模块中。
Sds在Redis中的用途主要有两个:
1.用于创建 stringObject 对象
2.在Redis内部作为char *的替代品。
1.实现字符串对象
Redis是一个键值对数据库,(key-value DataBase),数据库的值可以是字符串、集合、列表等多种类型的对象,而数据库的键则总是字符串对象。对于那些包含字符串值的字符串对象来说,每个字符串对象包含一个 sds 值。
2.将 sds 替代 C 默认的 char * 类型
C默认的char类型的字符串,功能单一,抽象层次低,并且不能高效的支持一些Redis操作(比如追加操作和长度计算操作),所以在Redis内部,绝大部分情况下会使用sds替代char*表示字符串。
在Redis中,客户端传入的协议内容、aof缓存内容、返回给客户端的回复等等,这些重要内容都是用sds类型保存的。
Redis中的字符串
在C语言中,字符串都是以'\0'结尾的。比如说 hello world 在c语言中表示为"hello wordl\0"
这种简单的字符串多数情况下可以满足要求,但是,它并不能高效的进行计算长度和追加的操作
1.计算长度操作需要使用 strlen()函数,复杂度为O(n)
2.如果追加N次,需要realloc N次
Redis中,这两种操作非常频繁,这两个简单的操作不能成为性能瓶颈。另外,Redis除了能处理字符串外,还要处理单字节的数组,以及服务器协议等内容,所以Redis的字符串还应该是二进制安全的。所以Redis采用Sds替代了C默认的char*字符串。sds既可以高效的进行计算长度和追加操作,还是二进制安全的。
sds的实现:
sds由两部分组成
其中sds 是char* 的别名,而结构 sdshdr则保存了len、free和buf三个属性。
通过len,可以轻易的计算出字符串的长度(O(1))。
另一方面,通过对buf多分配一些空间,并使用free记录未使用的空间的大小,sdshdr可以让直行追加操作所需要的内存重分配次数大大减少。
当然sds的操作都会正确的更新len、free属性。
优化追加操作
因为sdshdr有free这个属性,所以在分配空间的时候,可以多分配一些空间,这样在下一次追加操作的时候,不一定需要再次分配空间,减少重新分配空间的次数。
比如我们在 最初一个字符串的 "hello world\0" sdshdr值如下,
当我们Append的时候,Redis会重新分配空间,比如我们 append 一个字符串 again,只需要7个字节,但是Redis却分配了比所需空间大一倍的空间。机会分配出37个字节的空间,这样就多余了18个字节,那再下一次Append操作的时候,如果追加的字符串长度小于18个字节,就不用再次分配空间了,直到追加的时候,剩余空间不足够,才会在次重新分配空间,且又会分配2倍的空间。以此来减少重新分配空间的次数,但是多分配的空间,却不会回收,除非整个字符串所占用的空间都被销毁了。
总结:
1.Redis字符串表示为sds,不是C默认的char*
2.比起C字符串,sds有以下优势
2.1.方便计算字符串长度
2.2.追加操作更高效
2.3.二进制安全
3.sds为了优化追加操作,会多分配一些空间,但是多分配的内存不会主动回收,会浪费一点空间。
Sds在Redis中的用途主要有两个:
1.用于创建 stringObject 对象
2.在Redis内部作为char *的替代品。
1.实现字符串对象
Redis是一个键值对数据库,(key-value DataBase),数据库的值可以是字符串、集合、列表等多种类型的对象,而数据库的键则总是字符串对象。对于那些包含字符串值的字符串对象来说,每个字符串对象包含一个 sds 值。
2.将 sds 替代 C 默认的 char * 类型
C默认的char类型的字符串,功能单一,抽象层次低,并且不能高效的支持一些Redis操作(比如追加操作和长度计算操作),所以在Redis内部,绝大部分情况下会使用sds替代char*表示字符串。
在Redis中,客户端传入的协议内容、aof缓存内容、返回给客户端的回复等等,这些重要内容都是用sds类型保存的。
Redis中的字符串
在C语言中,字符串都是以'\0'结尾的。比如说 hello world 在c语言中表示为"hello wordl\0"
这种简单的字符串多数情况下可以满足要求,但是,它并不能高效的进行计算长度和追加的操作
1.计算长度操作需要使用 strlen()函数,复杂度为O(n)
2.如果追加N次,需要realloc N次
Redis中,这两种操作非常频繁,这两个简单的操作不能成为性能瓶颈。另外,Redis除了能处理字符串外,还要处理单字节的数组,以及服务器协议等内容,所以Redis的字符串还应该是二进制安全的。所以Redis采用Sds替代了C默认的char*字符串。sds既可以高效的进行计算长度和追加操作,还是二进制安全的。
sds的实现:
sds由两部分组成
typedef char *sds; struct sdshdr { // buf 已占用长度 int len; // buf 剩余可用长度 int free; // 实际保存字符串数据的地方 char buf[]; };
其中sds 是char* 的别名,而结构 sdshdr则保存了len、free和buf三个属性。
通过len,可以轻易的计算出字符串的长度(O(1))。
另一方面,通过对buf多分配一些空间,并使用free记录未使用的空间的大小,sdshdr可以让直行追加操作所需要的内存重分配次数大大减少。
当然sds的操作都会正确的更新len、free属性。
优化追加操作
因为sdshdr有free这个属性,所以在分配空间的时候,可以多分配一些空间,这样在下一次追加操作的时候,不一定需要再次分配空间,减少重新分配空间的次数。
比如我们在 最初一个字符串的 "hello world\0" sdshdr值如下,
struct sdshdr { len = 11; free = 0; buf = "hello world\0"; }
当我们Append的时候,Redis会重新分配空间,比如我们 append 一个字符串 again,只需要7个字节,但是Redis却分配了比所需空间大一倍的空间。机会分配出37个字节的空间,这样就多余了18个字节,那再下一次Append操作的时候,如果追加的字符串长度小于18个字节,就不用再次分配空间了,直到追加的时候,剩余空间不足够,才会在次重新分配空间,且又会分配2倍的空间。以此来减少重新分配空间的次数,但是多分配的空间,却不会回收,除非整个字符串所占用的空间都被销毁了。
总结:
1.Redis字符串表示为sds,不是C默认的char*
2.比起C字符串,sds有以下优势
2.1.方便计算字符串长度
2.2.追加操作更高效
2.3.二进制安全
3.sds为了优化追加操作,会多分配一些空间,但是多分配的内存不会主动回收,会浪费一点空间。
相关文章推荐
- Redis源码分析(五)——简单动态字符串(sds)
- (一)redis源码学习之简单动态字符串(SDS)
- 结合redis设计与实现的redis源码学习-2-SDS(简单动态字符串)
- Redis源码解析:01简单动态字符串SDS
- 【redis源码分析】动态字符串--sds
- redis源码分析笔记2- redis的数据类型-动态字符串sds
- Redis源码学习——简单动态字符串SDS(Simple Dynamic String)
- Redis源代码分析之五:简单动态字符串——Sds
- Redis源码阅读笔记(1)——简单动态字符串sds实现原理
- Redis源码分析二、Redis简单动态字符串
- Redis 源码解析 string内部实现原理之简单动态字符串SDS
- redis源码分析(二)、sds动态字符串学习总结
- Redis源码剖析--简单动态字符串sds
- Redis源码剖析(十)简单动态字符串sds
- redis源码分析(二)、redis源码分析之sds字符串
- redis内部数据结构--简单动态字符串sds
- redis 系列3 简单动态字符串 SDS
- Redis源码剖析和注释(二)--- 简单动态字符串
- redis源码解析1-简单动态字符串
- 《Redis设计与实现》阅读:Redis底层研究之简单动态字符串SDS