《Redis设计和实现》读书笔记1-简单动态字符串
临近过年,我离开了实习了4个多月的扇贝。临走前,导师赠送给我一本《Redis设计和实现》,于是心血来潮,想读一读这本书,然后仿照书中介绍的原理实现一个小型的数据库。这是redis系列的第一篇博文,希望我可以坚持下去,不要虎头蛇尾。
简单动态字符串
我们都知道Redis是由纯c代码编写而成的,而c语言中的原生字符串有很多的缺陷,不利于大型工程的使用。于是Redis的作者便自己实现一套字符串数据结构,就是sds.h/sdshdr结构。
SDS的定义
struct sdshdr {
// 记录sdshdr中数组已经使用的数量
int len;
// 记录sdshdr中数组未使用的数量
int free;
char buf[];
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
sdshdr
的定义如代码所示,其中buf
属性为一个char类型的数组,数组的前五个字节分别保存着’R’,’e’,’d’,’i’,’s’五个字符,最后一个字符则保存则空字符串’\0’。之所以在数组尾部保存空字符,是为了可以使用一些c语言的字符串函数库中的函数。
SDS与c字符串的区别
常数时间内获得字符串长度
我们都知道,在c中,字符串就是一个末尾有一个’\0’的一维数组,它并不记录本身的长度。所以,每次想要获取其长度时,都需要遍历整个数组,时间复杂度就为O(n);而SDS因为本身就有len
这个字段,并且在SDS被修改时,会自动改变len
字段,所以获得字符串长度的时间复杂度为O(1).
杜绝缓冲区溢出
因为c的字符串没有任何安全保证,当我们使用strcat
函数来拼接字符串时,如果目标字符串没有被分配足够空间的话,就会造成缓冲区溢出。而在SDS中,当然是每次修改都会进行缓冲区溢出检测,所以不会出现类似问题。
减少修改字符串时带来的内存重新分配次数
这一条应该是使用SDS最大的优势所在啦。因为c语言中的字符串都是无法修改的,所以每次拼接或者裁剪字符串都会导致新的字符串数据结构的生成,从而需要新的内存分配或者释放部分内存。由于内存分配很消耗时间,所以使用c语言的字符串会导致数据库性能低下。
而SDS会通过空间预分配和惰性空间释放来减少内存分配或者释放的次数。
内存预分配是指每次需要对SDS进行空间扩展时,程序不仅分配SDS所必须要的空间,还会额外分配一些空间,将其大小赋值给’free’属性。如果需要分配的大小为n,额外分配的空间为e,总共分配空间为t,那么(默认单位为字节)
e = n < 1MB ? n:1MB
t = n < 1MB ? n + n + 1 ? n + 1MB + 1
- 1
- 2
这样的话,下次再进行字符串拼接时,额外的空间就会被使用上,从而避免额外的一次内存分配。
而惰性内存回收则是指裁剪字符串时,释放出来的额外空间并不会立刻被回收,而是继续保存,只是修改len
和’free’属性,等到字符串再次被修改时使用。
二进制安全
由于c语言字符串以’\0’来判断字符串的结束,所以无法保存一些图片,音频,视频这些可能写入’\0’的二进制数据。
后续
书里的内容很简单,希望自己也可以实现一个简单的string类型吧,不过不清楚java中String对象的实现欧,以后可以了解一下。
文章来源: blog.csdn.net,作者:程序员历小冰,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/u012422440/article/details/50625981
- 点赞
- 收藏
- 关注作者
评论(0)