Redis设计与实现系列-基本数据结构-SDC

关于《Redis设计与实现》读书笔记java

SDC全称是(simple dynamic string,SDS),Redis是以C语言编写的,可是Redis并无直接使用C语言内置的字符串(C语言内置的字符串以空格结束),Redis本身构建了一套抽象字符串SDC用来描述Redis中使用的字符串,当且仅当使用字符串常量时Redis才会直接使用C语言字符串。redis

咱们使用Set命令设置一个键值对时,例如SET ls "hello",Redis将会在数据库中设置一个键值对,其中键值对的键是一个字符串对象,底层实现了一个保存ls的SDC对象;键值对的值也是一个字符串对象,底层实现了一个保存"hello"的SDC对象。数据库

若是咱们使用LPUSH指令设置一个列表,例如 RPUSH fruits "apple" "banana" "cherry",Redis将会在数据库中设置一个键值对,其中键值对的键也是一个字符串对象,底层实现了一个保存fruits的SDC对象,键值对的值是一个列表对象,列表中包含3个字符串,每一个字符串都是一个SDC对象。api

经过两个例子咱们对SDC有了简单的认识,简单地说SDC就是用Redis对C语言字符串的一个封装,可是这种封装在Redis中有着严格的定义,C语言中没有类这种概念,C语言中SDC是用一个结构体来描述SDC,具体定义在Redis中sds.h文件中,以下所示:数组

struct sdshdr {

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

    // 记录 buf 数组中未使用字节的数量
    int free;

    // 字节数组,用于保存字符串
    char buf[];

};

若是了解Java的同窗能够很明白,这种封装跟Java中的从java.lang.String类封装相似,显然len就是维护着字符串的长度,buf是一个char数组,Java中String也有这两个东西,其中free用于保存buf数据组中未使用的空间也很好理解。缓存

上图很形象地描述了SDC的定义,SDC跟C语言字符串同样分配了一字节空间存储'\0',这样有一个好处就是能够直接使用部分C语言字符串函数,例如:printf("%s", s->buf),这样就无需单独为redis设计打印函数了,殊途同归。安全

C字符串与redis字符串区别app

  • 常数时间复查度获取字符串长度,C字符串要获取字符串长度必须遍历字符串的每个字节直到遇到'\0'字符才能获取字符串长度,显然这是一个O(N)时间复杂度,SDC因为内置的字符串长度变量,所以只须要在常熟时间复查度就能够直接获取字符串长度,redis很大一部分是用做缓存使用,每一个地方的性能提高都对总体性能提高很是有用。
  • 杜绝缓冲区溢出,因为不记录字符串长度C字符串很容易形成缓冲区溢出,C语言中strcat函数能够将字符串拼接到某个字符串后面,使用这个函数的假设是目标对象分配了足够的内存,若是这个假设不成立将会形成缓冲区溢出致使其它内存区域的变量被修改。SDC则不会存在这个问题,SDC每次执行拼接操做时都会检查当前字符串长度看是否有足够的剩余空间,若是空间不够则对buf数组进行扩容。
  • 下降内存分配次数,C语言字符串每次执行拼接操做若是字符串内存容量不够都要进行扩容操做,不然将会形成缓冲区溢出;每次执行剪切字符串操做都要释放不须要使用的内存,不然会形成内存溢出。内存分配和释放涉及到系统调用是很是损耗系统性能的,redis做为一场很是苛刻的缓存数据库常常会用到字符串的长度变换若是每次都执行内存分配和释放将会给系统带来很大的压力。而在SDC中buf数组长度长度不必定就是当前字符串长度,buf内部能够包含未使用的空间,其中free就描述了未使用的空间大小。经过free SDC实现的空间预分配和惰性释放。
  • 空间预分配,空间预分配主要用于优化SDC的字符串增加操做,若是当前buff的未使用空间不能知足新的字符串增加须要,SDC不只仅分配新进字符串空间还会分配额外的空间,这样在下一次拼接字符串时就可能不须要再次分配空间了,必定程度降低低了内存分配次数。
  • 空间惰性释放,空间惰性释放主要用于优惠字符串缩短操做,当字符串缩短时并非当即使用内存空间而是使用free记录,这样下次要执行拼接操做时可能就不须要进行空间分配了,固然redis也经过API主动对未使用的内存进行释放。
  • 二进制安全,C字符串必须是某种编码格式,并且字符串内部不能包含空字符串,不然会被视为字符串结尾,这就限制了C字符串只能保存文本信息不能保存视频、图片等二进制信息,redis的api都是二进制安全的,不只仅能保存文本信息也能够保存二进制信息,redis api都会以处理二级制信息来处理保存在buf中的信息不会对其进行过滤限制。
  • 兼容部分C字符串函数,好比printf函数(上面提到)。
相关文章
相关标签/搜索