本文主要是介绍理解Redis SDS(简单动态字符串),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
简述
Redis中并没有直接使用C语言的字符串表示(在内存中以“\0”作为字符串的结尾),而是自己新建了一个字符串的结构,该结构就是SDS(Simple Dynamic String,简单动态字符串)。
SDS在Redis中的使用
Redis中设计可变字符串都是用的SDS结构,如Redis底层为键值对结构,所有的键都是字符串类型的,就是SDS结构的对象。当然Redis打印日志时,字符串不需要变化,则是使用的C语言的字符串。
SDS结构
struct sdshdr{//buf数组中未使用的字节数量int free;//buf数组中已经使用的字节数量,不包括“\0”int len;//字节数组,用来保存字符串char buf[];
}
假如用SDS来存储字符串“Redis”,那么其结构如下:
len为5,实际buf数组的长度为6,有一个字节用来存储了“\0”。SDS不需要“\0”来判断字符串是否到结尾,那么为什么还要在buf数组最后用“\0”作为结尾呢?其实主要是Redis还要用到C语言中对字符串的处理函数,以“\0”作为结尾,Redis就可以使用这些函数而不用自己去实现。
SDS与C语言字符串的区别
获取字符串长度时时间复杂度O(1)
在C语言的字符串中,以"\0"作为结尾,在需要求字符串长度的时候,需要遍历数组到“\0”处,时间复杂度为O(N)。而在SDS的结构中,可以直接从len中读取长度,时间复杂度为O(1)。
缓冲区溢出问题
传统C语言字符串在执行诸如字符串相加的函数时,是假设使用者已经进行了内存的分配,有足够的内存可以供操作,假如使用者在执行函数之前没有进行内存处理,就可能出现缓冲区溢出的情况。
如:现在有两个字符串S1,S2,结构如下:
此时,如果直接给S1加上“ Cluster”,就会发生溢出,结构变为:
可以看到S2的字符串变为“Cluster”。而SDS结构中free字段,明确规定了buf数组空闲字节的数量,执行操作之前可以计算free是否足够放下新的字符串,如果不够就进行内存分配,这样就可以防止缓冲区溢出。
减少内存分配的次数
传统的C语言字符串,在进行字符串相加操作之前,每一次操作都需要进行内存分配,防止缓冲区溢出。而SDS,如果free空闲字节数量足够,完全可以直接进行操作,不需要进行空间申请。那么SDS是怎么判断应该预留多少free的呢?
空间预分配
假如free中空闲的字节数不足以放下新的字符串,那么SDS也会申请进行内存分配,保证buf足够的空间放下新的字符串。当存储的字符串大小小于1MB时,free会和len一样大,也就是假设新的字符串大小len为13,那么free也为13,buf数组的长度为13 + 13 + 1(\0占一位)。如果新的字符串超过1MB,那么free就为1MB。
惰性释放内存空间
buf存储的字符串进行缩减操作时,内存空间并不会立刻释放,释放出来的字节数目会加到free中。
二进制安全
传统的C语音字符串是无法保存媒体数据的,因为如果数据中有“\0”就会被判断为结尾。使用SDS就可以存储媒体数据。
注:"\0"是 ASCII 码为 0 的字符,对应的字符是(Null),C语言中用来判断字符串的结尾
这篇关于理解Redis SDS(简单动态字符串)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!