Redis设计原理与实现 Redis字符串设计

Redis字符串设计

  1. Simple dymatic string SDS字符串设计
  2. SDS对象
		//sds字符串
       int free;	2	//当前字符串空间剩余未分配长度
       int len;	4	//当前字符串总长度
       char[] buf;		//当前字符串保存	'a' 'b' 'c' '' 'd' '\0' 空格 空格

SDS字符串扩展规则:

  • SDS的预修改,是先给与free足够的空间,然后扩展字符串
  • 如果对SDS进行修改以后,SDS的长度(也就是len属性的值)将小于1MB,那么程序分配和len属性同样大小的未使用空间,这时候SDS的len和free属性的值相同。
  • 如果对SDS进行修改以后,SDS的长度将大于1MB,那么程序会分配1MB的未使用空间。
    SDS的buf数组的实际长度会变成 len+free+1byte (1byte是buf最后的空字符,表示字符串的结尾。C语言字符串设计也是如此。)
  • 惰性空间释放:当字符串缩减以后,并不直接释放对应空间,而是先将不用的内存空间保留在free中,留待下次使用。并且可以通过SDS的API来释放空间。
C字符串 											SDS
获取字符串长度的复杂度是o(N)						获取字符串长度的复杂度是o(1)
API是不安全的,可能会造成缓冲区溢出或者内存泄漏		API是安全的,不会造成缓冲区溢出
修改字符串长度N次必然需要执行N次内存重分配				修改字符长度N次最多需要N次内存重分配
只能保存文本数据									可以保存文本或者二进制数据('\0'的处理方式不同)
可以使用所有<string.h>库中的函数					可以使用部分<string.h>库中的函数

详解:

  • 因为C语言(纯面向过程,没有对象的概念)中字符串就是一个数据,本身不记录长度,故strLen的时间复杂度是 o(N)——而在SDS中记录了字符串的长度,故strLen的时间复杂度是o(1)
  • 除了获取字符串长度的复杂度高之外,C字符串不吉利自身长度带来的另一个问题是容易造成缓冲区溢出(buffer overflow——与C字符串不同,SDS的空间分配策略完全杜绝了发生缓冲区溢出的可能性:当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的需求,如果不满足的话,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作。
  • C字符串修改长度,会执行N次内存重分配——SDS字符串修改长度,至多执行N次内存重分配,因为SDS里面有fre空间
  • C字符串中的字符必须符合某种编码(例如ASCll),并且处理字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被认为是字符串结尾。这些限制使得C字符串只能保存文本数据,而不能保存像图片、视频、视频等二进制数据。—— 在SDS里面通过len记录了字符串的长度。故不用担心这个问题。
  • SDS字符串保留了C字符串中,最后一个字符是 ’\0‘ 的规则,可以重用部分<string.h>库中的函数

小结

  1. Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS作为字符串表示
  2. 比起C字符串,SDS具有以下有限
    2.1 常数复杂度获取字符串长度
    2.2 杜绝缓冲区溢出
    2.3 减少修改字符串长度所需的内存重分配次数
    2.4 二进制安全
    2.5 兼容部分C字符串函数

备注:
如果程序执行的增长字符串的操作,比如拼接操作,那么在执行这个操作之前,程序需要先通过内存重分配来扩展底层数组的空间大小——如果网络这一步就会产生缓冲区溢出


如果程序执行的是缩短字符串的操作,比如截断操作,那么在执行这个操作之后,程序需要通过内存重分配来释放字符串不再使用的那部分空间——如果忘了这一步就会产生内存泄漏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值