#1:SDS介绍
我们在redis中执行命令

set key name

的时候,key和name都是字符串类型,而且字符串(string)在redis中是会经常用到的类型,那redis是如何保存字符串的呢?我们接下来往下看
众所周知,redis是c写的,在c中使用char来保存字符串,并且用\0作为字符串的结尾,但是redis不是这样保存的,redis是使用一种叫SDS的结构来保存字符串的。结构如下(redis3.2以前)

 struct sdshdr{   int len;   int free;   char buf[];}

那么问题来了,redis为什么 会用SDS的结构,而不直接用c语言的字符串,我们来看看他们的区别
###1:计算字符串长度的区别
对于c来说,计算字符串的长度的方式就是遍历,遇到\0就停止,所以复杂对是O(n),而SDS直接保存了字符串的长度,复杂度是O(1)
###2:保证二进制的安全
因为SDS并不是以\0为结尾的标志,自然就保证了二进制的安全
###3:内存管理策略(预分配内存和惰性空间释放策略)
redis是一个高速的缓存数据库,需要频繁的对字符串进行操作,如果内存分配错误,会导致很严重的后果,就算内存分配没问题,频繁的内存分配也是非常耗费时间的,所以这些都是应该去避免的
#####惰性空间释放策略
在SDS中首先用到了惰性空间释放策略,惰性空间释放用于优化SDS的字符串缩短操作。
当要缩短SDS保存的字符串时,程序并不立即使用内存充分配来回收缩短后多出来的字节,而是使用表头的free成员将这些字节记录起来,并等待将来使用。
源码如下

void sdsclear(sds s) {  //重置sds的buf空间,懒惰释放    struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));    sh->free += sh->len;    //表头free成员+已使用空间的长度len = 新的free    sh->len = 0;            //已使用空间变为0    sh->buf[0] = '\0';         //字符串置空}

#####预分配内存
扩容策略是字符串在长度小于 1M 之前,扩容空间采用加倍策略,也就是保留 100% 的冗余空间。当长度超过1M 之后,为了避免加倍后的冗余空间过大而导致浪费,每次扩容只会多分配 1M大小的冗余空间。
###4:兼容c语言函数库 (字符串后面会自动加上\0)
#3.2版本以后的SDS结构
前面的len和free以及char这种结构看起来很好,但是是存在一定的问题的

 struct sdshdr{   int len;   int free;   char buf[];}

len和free都是int类型,都是4byte也就是32bit,能表示42亿左右的范围,大大的造成了空间的浪费,所以在3.2以后对SDS有一定的更改,更改如下

typedef char *sds;/* Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings. */struct __attribute__ ((__packed__)) sdshdr5 {    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */    char buf[];};struct __attribute__ ((__packed__)) sdshdr8 {    uint8_t len; /* used */    uint8_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};struct __attribute__ ((__packed__)) sdshdr16 {    uint16_t len; /* used */    uint16_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};.........

sdshdr5表示的是用5个bit位来表示数据的长度,sdshdr8就是表示用8个bit位来表示数据的长度,以此类推
sdshdr5的内存分配如图

当需要存储的数据长度超过31,就需要用sdshdr8来表示
sdshdr8的内存分配如图

其余的sdshdr16以上的都是以此类推,判断方式源码如下

static inline char sdsReqType(size_t string_size) {    if (string_size < 1<<5) //2^5-1        return SDS_TYPE_5;    if (string_size < 1<<8) //2^8-1        return SDS_TYPE_8;    if (string_size < 1<<16) //2^16-1        return SDS_TYPE_16;#if (LONG_MAX == LLONG_MAX)    if (string_size < 1ll<<32) //2^32-1        return SDS_TYPE_32;    return SDS_TYPE_64;#else    return SDS_TYPE_32;#endif}

关注我的技术公众号,每周都有优质技术文章推送。
微信扫一扫下方二维码即可关注:

©著作权归作者所有:来自51CTO博客作者wx5926490d23476的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. JavaScript中的基本字符串与字符串对象的区别
  2. 【正则】整理详细JavaScript正则表达式入门,看这篇就够了!附常用的
  3. 换肤案例以及选项卡
  4. 4.07字符串与数组的一些常用方法
  5. (lintcode)第8题旋转字符串
  6. (lintcode)第13题字符串的查找
  7. (lintcode)第29题交叉字符串
  8. js基础知识:字符串数组方法及留言本实例
  9. 留言板添加字数实时统计和超出判断以及数组字符串方法

随机推荐

  1. Android应用开发基础之数据存储和界面展
  2. GridView使用相关问题
  3. 将Linux下的Android签名对pk8和pem转换为
  4. Android开发,使用xml drawable制作带边框
  5. android fragment(android.support.v4.app
  6. Android回炉系列之Surfaceflinger
  7. android 自定义侧边栏
  8. 查看基于Android(安卓)系统单个进程内存
  9. Building the System Android
  10. ListView美化(2)-android:cacheColorHint