简单动态字符串
传统上的C语言的字符串表示是以空字符结尾的字符数组(C字符串),redis自己实现一个动态字符串(SDS),两者之间的区别以及使用SDS的好处有:
- 结构不同。C字符串以空字符结尾的字符数组,而SDS表现的更为复杂,使用一个结构体来表示一个SDS,如图所示。其中,free属性表示buffer字符数组中剩余的空间,len表示已经使用的空间。另外,SDS遵守C字符串的惯例,以空字符结尾,这样就可以复用一些C字符串的API,例如打印函数等。
- 常数级别的读取字符串长度。C字符串每次读取length都需要遍历一次buffer数组,而SDS通过返回len属性直接得到长度。
- 防止数据溢出。C字符串在创建时需要分配一定的空间,如果两个字符串s1,s2在内存空间紧密相连,这时对字符串s1后面添加一个字符串,而又忘记为s1重新分配足够的空间,那么s1数据将溢出到s2的空间上;而SDS通过判断free属性来判断当前空余空间是否充足来保证正确的字符串增加等。
- 采用预空间分配和惰性空间释放减少修改字符串带来的内存重分配次数。预空间分配:当对SDS修改并且free空间不足,需要进行扩展,在补充不足空间的同时也会增加free的值;如果buffer的长度小于1M,那么扩展后的buffer长度等于len+free+1byte,free=len;如果buffer长度大于等于1M,那么扩展后的buffer长度等于len+1M+1byte。惰性空间释放:当执行字符串缩减时,不用释放空间,直接将需要释放的空间纳入到free中,减少内存释放以及重分配的次数。
- 二进制安全。C字符串只能保存文本数据,不能保存音频,图像,压缩文件等二进制文件(因为C字符串以\0结束),而SDS可以,因为SDS不是利用空字符来判断字符串结束,而是通过len属性来判断。
另外,SDS也兼容了C字符串的一些API(因为在buffer数组使用C字符串的惯例以空字符结尾),这样的好处就是redis不用自己在重新实现,可以复用一部分C字符串的API。
本文为《Redis设计与实现》阅读笔记