底层实现-SDS 简单动态字符串

原创 2016年05月30日 16:53:14
一 介绍

  • Redis只会使用C字符串作为字面量,大多数情况下,Redis使用SDS(Simple Dynamic String,简单动态字符串)作为字符串表示。
  • 也就是说,Redis中字符串的底层实现,一般就是SDS。
  • 底层依赖于C的标准类型 - 数组。

SDS与C字符串的不同

  • 获取字符串长度更容易
        SDS加了元数据len与free,获取字符串长度的时间复杂度是O(1)。获取C字符串需要遍历整个字符串,直到遇到'\0'为止,所以时间复杂度是O(n)

  • 杜绝缓冲区溢出
        因为C字符串不记录自身的len与free,做strcat字符串合并这样的动作时,如果src本身空间不足以容纳dst,那么就就溢出并影响到紧接着的内存,使得后面的内存值被修改。SDS因为记录了len与free,做合并之前会先看空间是否满足,不够的话会先进行扩展,然后才执行拼接操作。

  • 减少修改字符串时带来的内存重分配次数
        C字符串的增减都需要进行一次内存重分配的操作,如append追加,必须先执行内存重分配来拓展底层数组的空间大小,如果忘了这一步,会产生缓冲区溢出。如果执行trim截断,那么在执行这个操作后,程序需要通过内存重分配来释放字符串不再使用的空间,否则会发生内存泄露。(内存泄露:申请了的空间实际未必都用上,这部分也无法被OS回收,长此以往,会使机器内存资源耗尽)。内存重分配要通过系统调用,对于Redis这种数据频繁修改的程序,频繁的系统调用会消耗掉很大部分性能。所以SDS解除了字符串长度与底层数组的一一对应。在SDS中,buf数组的长度不一定就是字符数量加1,数组里面可以包含未使用的字节,而这些字节的数量由SDS的free属性记录。
  1.    空间预分配
        用于优化SDS的字符串增长操作,连续增长N次字符串所需的内存重分配次数,从N次降低为最多N次。如果对SDS进行修改后,SDS长度(len)少于1MB,那么把free字段也设置成len字段的值。也就是说修改后SDS使用率是50%。如果大于等于1MB,那么FREE就不会那么激进去double一下len,程序会分为1MB的未使用空间,free是1MB。此时的使用率是小于等于50%的。通过预分配策略,减少增长字符串时所做的内存重分配带来的系统调用开销。要拓展SDS字符串时,会先看SDS的free空间是否足够容纳新的字符,如果能,就不会去拓展SDS的空间了。
  1.     惰性空间释放
        用于优化SDS的字符串缩短操作。当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些自己的数量记录起来,并等待将来使用。当然,SDS也有相应的API,让我们可以在有需要时,真正地释放SDS的未使用空间,所以不用担心浪费。

  • 二进制安全
        SDS的buf是字节数组,保存的是二进制数据,而不是字符。C语言的字符串,除了末尾,中间不能出现'\0'字符,否则会被误会成是字符串结尾。万一有些图片、音频、视频、压缩文件数据,中间有多个'\0',这样C一读到就以为结束了,这样是不行的,这些限制使得C字符串只能保存文本数据。SDS的API是二进制安全的,数据写入时是怎么样,读出就是怎么样,保存怎么样的数据都可以。SDS可以做到这样,主要是因为SDS是根据len来判断字符串是否到了末尾,而不是根据'\0'来判断。

  • 兼容部分C字符串函数
        为了可以重用一部分C标准函数,SDS的API在保存数据时,以为在末尾设置'\0'字符,并且在为buf分配空间的时候多分配一个字节来容纳空字符。例如使用<string.h>的strcasecmp(sds->buf,'hello world')与strcat(c_string,sds->buf),就不用专门另外编写一个实现这些功能的函数了。

总的来说,就是字符串加了len与free这两个元数据,使得实现一些算法更容易。

C字符串 与 SDS 的区别

源码
sds.h
sds.c


二  数据结构

struct sdshdr {
    unsigned int len;    // buf中已占用的长度,不包括空字符
    unsigned int free;  // buffer中剩余可用长度
    char buf[];             // 实际保存字符串数据的数组
};




三  sds主要的api



主要是对sds、sds里面数组内容的增删查改。





【Redis源码剖析】 - Redis内置数据结构之字符串sds

今天花了一个晚上的时间分析了Redis中字符串操作的实现,源文件为sds.h和sds.c。...
  • Xiejingfa
  • Xiejingfa
  • 2016年03月28日 21:07
  • 3879

Redis源码剖析和注释(二)--- 简单动态字符串

Redis 简单动态字符串1.介绍Redis兼容传统的C语言字符串类型,但没有直接使用C语言的传统的字符串(以’\0’结尾的字符数组)表示,而是自己构建了一种名为简单动态字符串(simple dyna...
  • men_wen
  • men_wen
  • 2017年04月06日 16:39
  • 850

redis 数据结构之和对象---简单动态字符串SDS(simple dynamic string)

1.介绍: reids 没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组)而是构建了一种名为简单动态字符串的抽象类型,并为redis的默认字符串表示,因为C字符串不能满足redis对字符串...
  • i_bruce
  • i_bruce
  • 2014年11月08日 16:19
  • 822

【Redis源码剖析】 - Redis内置数据结构之字符串sds

今天花了一个晚上的时间分析了Redis中字符串操作的实现,源文件为sds.h和sds.c。...
  • Xiejingfa
  • Xiejingfa
  • 2016年03月28日 21:07
  • 3879

C++中string类和Redis中SDS的比较

Redis中SDS与C++中string类的比较
  • wrx1721267632
  • wrx1721267632
  • 2016年03月23日 13:14
  • 370

Redis深入理解-数据结构篇(1)-简单动态字符串SDS

Redis没有直接使用C语言中的字符串,而是自己构建了SDS这样的一种简单动态字符串,并且将他作为Redis中字符串的默认的表示,个人认为,Redis并未完全抛弃C语言字符串,只不过是在C语言字符串的...
  • wangyang1354
  • wangyang1354
  • 2016年10月03日 13:02
  • 2570

Redis内部数据结构详解之简单动态字符串(sds)

本文所引用的源码全部来自Redis2.8.2版本。 Redis中简单动态字符串sds数据结构与API相关文件是:sds.h, sds.c。 转载请注明,本文出自:http://bl...
  • Acceptedxukai
  • Acceptedxukai
  • 2013年12月22日 13:54
  • 7674

Redis源码分析(四)-- sds字符串

今天分析的是Redis源码中的字符串操作类的代码实现。有了上几次的分析经验,渐渐觉得我得换一种分析的方法,如果每个API都进行代码分析,有些功能性的重复,导致分析效率的偏低。所以下面我觉得对于代码的分...
  • Androidlushangderen
  • Androidlushangderen
  • 2014年10月08日 20:29
  • 5746

Redis -- 1、简单动态字符串(sds)

一个纯粹用C写的nosql。 严重 参考以下链接 http://www.redisbook.com/en/latest/#redis 1、简单动态字符串(sds) 作用有两:实现字符串对象;在r...
  • sophie_stef
  • sophie_stef
  • 2013年11月28日 16:42
  • 376

绿盟科技发布2015软件定义安全SDS白皮书

业界对云计算的研究及实践由来已久,但随之来而的云安全问题,需要有一套云环境中的安全建设及运维的框架和方法,同时更需要用户、云计算厂商与安全厂商多方协作实践的经验。面对这样的挑战,多年来,绿盟科技与国际...
  • SDNLAB
  • SDNLAB
  • 2015年09月14日 14:56
  • 1055
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:底层实现-SDS 简单动态字符串
举报原因:
原因补充:

(最多只允许输入30个字)