Redis-简单动态字符串

Redis SDS与C字符串区别

Redis没有直接使用C语言传统的字符串,而自己构建了一种简单动态字符串(Simple Dynamic String)的抽象类型,简称为SDS。并将SDS作为Redis的默认字符串表示。
例如:当我们在redis-client执行如下的命令时;

redis 127.0.0.1:6379>set message 'Hello World'
OK

那么Redis将会在数据库中创建一个新的键值对,其中:
* 键值对的键是一个字符串对象,对象底层的实现是一个保存着字符串“msg”的SDS。
* 键值对的值也是一个字符串对象,对象底层的实现是一个保存着字符串“Hello World”的SDS。

SDS的定义

每个sds.h/sdshdr结构表示一个SDS值:

struct sdshdr{
    
     int len; //记录buf中已使用字节的数量等于SDS所保存的字符串的长度
     
     int free; //记录buf中未使用字节的长度

     char []buf; //字节数据,保存字符串
}

SDS的优点

获取字符串的长度

Redis获取字符串长度可以通过SDS中的len属性来获得,时间复杂度为O(1)。而C语言获取字符串需要去遍历char数据来叠加获得,时间复杂度为O(n)。这就保证了在获取字符串长度时不会成为Redis的性能瓶颈。

杜绝缓存区溢出

除了获取字符串长度复杂度高之外,C语言不记录自身字符串长度带来的另一个问题是容易造成缓存区溢出(Buffer Overflow)。SDS属性len可以记录自身字符串的长度,因此当对SDS字符串进行拼接时,SDS API会先去检测buf的空间,如果空间不足,SDS先会扩容buf的空间,之后进行拼接。反之,直接去拼接。

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

空间预分配

空间预分配用于优化SDS字符串增长操作,当SDS的API对SDS的字符串进行修改,并且要对SDS进行空间扩展的时候,程序不仅会为SDS分配修改所必须要的空间,还会为SDS分配额外未使用的空间。分配公式主要有SDS中的len属性的大小决定。当len属性值小于1MB时,buf数组的实际长度为 len(修改后的len值)*2+1byte,这时len和free相等,一个字节用于保存空字符。当len属性值大于1MB时,buf数组的实际长度为 len(修改后的len值)+1MB+1byte,这时free的值为1MB。通过内存预分配策略,Redis可以减少连续执行字符串增长操作所需要的内存重分配次数。

惰性空间释放

惰性空间释放用于优化SDS字符串缩短操作:当SDS的API需要缩短SDS所保存的字符串时,程序并不立即去使用内存重分配来回收字符串缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来并等待将来使用。

二进制安全

由于SDS是通过len属性来判断字符串是否结束的,而不是使用空字符串来判断字符串是否结束的,并且SDS的API都是二进制安全的,所有的SDS API都会以处理二进制的方式来处理SDS存放在buf数组中的数据,程序不会对数组中的数据进行任何的过滤,限制,假设,数据在写入和读出的时候是一致的。

兼容部分C字符串函数

虽然SDS API是二进制安全的,但它依然遵循C字符串以空字符结尾的惯例。

总结

C语言字符串 SDS
获取字符串长度的时间复杂度为O(N) 获取字符串长度的时间复杂度为O(1)
API是不安全的,可能会造成缓存区溢出 API是安全的,不会造成缓存区溢出
修改字符串N次必须需要执行N次内存重分配 修改字符串N次最多需要执行N次内存重分配
只能保存文本数据 可以保存文本和二进制数据
可以使用所有的<string.h>函数 可以使用部分<string.h>函数

SDS API

函数 作用 时间复杂度
sdsnew 创建一个给定包含C字符串的SDS O(N),N为给定C字符串的长度
sdsempty 创建一个不包含任何内容的空 SDS O(1)
sdsfree 释放给定的SDS O(N),N为被释放的SDS的长度
sdslen 返回SDS已使用的字节数 可以直接去读取SDS的len属性,O(1)
sdsavail 返回SDS未使用的字节数 可以直接去读取SDS的free属性,O(1)
sdsdup 创建一个给定SDS的副本(copy) O(N),N为给定SDS的长度
sdsclear 清空给定的SDS字符串内容 使用惰性空间释放策略,O(1)
sdscat 将给定的C字符串拼接到SDS字符串的末尾 O(N),N为拼接C字符串的长度
sdscatsds 将给定的SDS字符串拼接到另一个SDS字符串的末尾 O(N),N为拼接SDS字符串的长度
sdscpy 将给定的C字符串复制到SDS中,覆盖原来SDS中的字符串 O(N),N为被复制C字符串的长度
sdsgrowzero 用空字符串将SDS扩展到指定的长度 O(N),N被扩展的新增字节数
sdsrange 保留SDS给定区域的数据,不在区域的数据覆盖或者清除 O(N),N被保留的字节数
sdstrim 接受一个SDS和C字符串的参数,从SDS中移除所有在C字符串中出现过的字符 O(N*N),N为给定C字符串的长度
sdscmp 对比两个SDS是否相等 O(N),N两个SDS中len较小的值
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容