SDS动态字符串(SDS)与C字符串的区别:
1.C语言对字符串长度的统计,就完全来自遍历,
SDS自己本身就保存了长度的信息
2.杜绝缓冲区溢出。C是不记录字符串长度的,一旦我们调用了拼接的函数,如果没有提前计算好内存,是会产生缓存区溢出的。SDS结构存储了当前长度,还有free未使用的长度。
3.减少修改字符串时带来的内存重分配次数。C语言字符串底层也是一个数组,每次创建的时候就创建一个N+1长度的字符。Redis为了避免C字符串这样的缺陷,就分别采用了两种解决方案:1空间预分配。2惰性空间释放
4.二进制安全。
SDS数据结构优化:
1.在 Redis3.x 版本中不同长度的字符串占用的头部是相同的,如果某一字符串很短但是头部却占用了更多的空间,这未免太浪费了。所以我们将 SDS 分为三种级别的字符串:
-
短字符串(长度小于32),len和free的长度用1字节即可;
-
长字符串,用2字节或者4字节;
-
超长字符串,用8字节。
我们可以在 SDS 中新增一个 type 字段来标识类型,但是没必要使用一个 4 字节的int类型去做!可以使用 1 字节的char类型,通过位运算(3位即可标识2^3种类型)来获取类型。
对齐填充
Redis选择不对齐,原因:
有个细节各位需要知道,即 SDS 的指针并不是指向 SDS 的起始位置(len位置),而是直接指向buf[],使得 SDS 可以直接使用 C 语言string.h库中的某些函数,做到了兼容,十分nice~。
如果不进行对齐填充,那么在获取当前 SDS 的类型时则只需要后退一步即可flagsPointer = ((unsigned char*)s)-1
;相反,若进行对齐填充,由于 Padding 的存在,我们在不同的系统中不知道退多少才能获得flags,并且我们也不能将 sds 的指针指向flags,这样就无法兼容 C 语言的函数了,也不知道前进多少才能得到 buf[]