在c中,字符串的表示一般是以\0(空字符)结尾的字符数组,这种表示字符串的方法简单,但是使用起来却有着许多繁琐事项,因此redis引入了自身的字符串形式->SDS。
那么c语言中的字符串数组具体来说有着哪些不足呢?总体来说,就是四点:
- 无法常数级获取长度,因为根本没有记录长度的数据,只能遍历直到遇到空字符串,而在特定情境下,获取长度可能是高频操作(很多使用者并不会认为获取长度是复杂的)
- 需要程序员自己去保证内存足够(否则缓冲区溢出问题就来了)
- 无论是空间的获取还是空间的释放都需要程序员考虑(而且因为需要和操作系统打交道,效率很低)
- 由于依赖\0来判断结束,所以在处理二进制(大量\0)的时候会显得力不从心
其实我们也可以看出来,这四个问题,其实涉及到的就是两点,第一个就是对于结束的判断(依赖于\0),第二点就是内存的分配。
因此SDS对此做出了两点改进,针对第一个问题,就是简单粗暴了,我直接维护一个长度不就行了?(而且在所有设计的api中都维护这个长度。第二点的话,SDS引入了一个free的概念来表达我还剩多少空间,通过这个参数,redis可以快速的判断是否会出现内存不够的问题,于是就可以避免缓冲区溢出的问题,而为了减少内存的重分配,redis在获取内存的时候并不是需要多少拿多少,而是采取这样的策略1.如果操作后的空间小于1MB,那么我就分配一样的free空间(2倍原则,这在算法里面也曾经出现过,通过这种分配,可以让数组延伸的时候的时间复杂度均摊为常数级),而如果大于1MB那么我就只分配1MB(否则太大了)
尽管SDS并不跟字符串数组相同,redis还是在实际存储的时候遵循了相同原则(以\0结束),这样就使得redis可以借用一部分使用字符数组的函数.
struct sdshdr{
int len;
int free;
char buf[];
}