一、基本原理redis
Redis 的字符串是动态字符串,是能够修改的字符串,内部结构实现上相似于 Java 的 ArrayList,采用预分配冗余空间的方式来减小内存的频繁分配,如图中所示,内部为当前字符串实际分配的空间 capacity 通常要高于实际字符串长度 len。当字符串长度小于 1M 时, 扩容都是加倍现有的空间,若是超过 1M,扩容时一次只会多扩 1M 的空间。须要注意的是 字符串最大长度为 512M。api
二、数据结构安全
struct sdshdr { // buf 中已占用空间的长度 int len; // buf 中剩余可用空间的长度 int alloc; //前3位为数据类型,后5位暂时没有用到 unsigned char flags; // 数据空间 char buf[]; };
三、SDS 与C字符串的对比 和优势数据结构
a O(1) 获取字符串长度函数
由于sds已经存了数据的长度,因此获取字符串长度复杂度为O(1),而C字符串获取长度为O(n)。优化
b 杜绝缓冲区溢出致使的内存问题编码
假设内存区域有s1:“hi”,s2: “redis” 两个字符串,位置紧邻,以下图: 紧邻字符串被覆盖 此时须要给s1 追加一个“boy”, 若是是C字符串,忘记了在追加以前先给s1 分配空间,此时追加将致使 s2的值被意外的修改。 而使用 sds则不会有这个问题。 由于其封装好的函数,会在追加数据以前先检查 空间是否够用,若是不够用就扩容。code
c 经过空间预分配和空间惰性释放图片
减小内存分配问题 当给sds的值追加一个字符串,而当前的剩余空间不够时,就会触发sds的扩容机制。扩容采用了空间预分配的优化策略,即分配空间的时候:若是sds 值大小< 1M ,则增长一倍; 反之若是>1M , 则当前空间加1M做为新的空间。 当sds的字符窜缩短了,sds的buf内会多出来一些空间,这个空间并不会立刻被回收,而是暂时留着以防再用的时候进行多余的内存分配。这个是惰性空间释放的策略内存
d 二进制安全
c字符串必须符合某种编码(例如ASCII),且不能包含空字符。 这些限制使得 c字符窜不能保存图片,音频等二进制文件。 而sds的api 都是二进制安全的,其全部api 都会以处理二进制的方式来处理buf内的数据,因此不会有任何的限制。