Redis之SDS

1、概述

        Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。

        当Redis需要的不仅仅是一个字符串字面量,而是一个可以被修改的字符串值时,Redis就会使用SDS来表示字符串值。

2、SDS结构

struct sdshdr {
    // 记录buf数组中已使用字节的数量
    // 等于SDS所保存字符串的长度
    int len;

    // 记录buf数组中未使用字节的数量
    int free;

    // 字节数组,用于保存字符串
    char buf[];
};

示例如下:

        如上所示:SDS遵循C字符串以空字符结尾的惯例,保存空字符的1字节空间不计算在SDS的len属性里面,并且为空字符分配额外的1字节空间,以及添加空字符到字符串末尾等操作,都是由SDS函数自动完成的,所以这个空字符对于SDS的使用者来说是完全透明的(使用者不用理会)。 

3、SDS与C字符串的区别

  • SDS保有一个字符串长度属性Len,因此获取SDS长度的复杂度为O(1)

         C语言字符串并不记录自身的长度信息,因此要获取一个C字符串的长度,程序必须遍历整个字符串,直到遇到代表字符串结尾的'\0'为止,此操作的复杂度为O(N)。与C字符串不同,由于SDS采用len属性记录了字符串本身的长度,因此获取一个SDS长度的复杂度仅为O(1)。

  • 杜绝缓冲区溢出

        C字符串不记录自身长度还会带来另外一个问题,那就是缓冲区溢出。例如strcat(char *dest,char *src)拼接字符串时,如果dest分配的内存不足以容纳所有的内容,则会发生缓冲区溢出,会意外的修改其他内存区域。

        与C字符串不同,SDS的空间分配策略完全杜绝了缓冲区溢出的可能。当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作。

  • 减少修改字符串时带来的内存重分配次数 

        在C语言中,当我们要增长字符串时,如拼接字符串,程序需要先通过内存重分配来扩展底层数组的空间大小,以访出现缓冲区溢出。而当我们要缩短字符串时,如截断操作,程序需要通过内存重分配来释放字符串不再使用的那部分空间 ,以访出现内存泄漏

        为了避免C字符串的这种缺陷,SDS通过未使用空间解除了字符串长度和底层数组长度之间的关联:在SDS中,buf数组的长度不一定就是字符数量加一,数组里面可以包含未使用的字节,而这些字节的数量就由SDS的free属性记录。通过未使用空间,SDS实现了空间预分配和惰性空间释放两种优化策略。

1)空间预分配

        空间预分配用于优化SDS的字符串增长操作:当SDS的API对一个SDS进行修改,并且需要对SDS进行空间扩展的时候,程序不仅会为SDS分配修改所必须要的空间,还会为SDS分配额外的未使用空间通过空间预分配策略,Redis可以减少连续执行字符串增长操作所需的内存重分配次数

        在扩展SDS空间之前,SDS API会先检查未使用空间是否足够,如果足够的话,API就会直接使用未使用空间,而无须执行内存重分配。

2)惰性空间释放

        惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待将来使用。

  • 二进制安全

        SDS的API都是二进制安全的(binary-safe),所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设,数据在写入时是什么样的,它被读取时就是什么样。因此,就算保存的字符串中间包含有\0结束符,也不会有什么问题。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis中的SDS(Simple Dynamic Strings)使用空间预分配策略来优化字符串的增长操作。当需要对SDS进行修改并且需要扩展SDS的空间时,Redis会为SDS分配修改所需的空间,并额外分配一些未使用的空间。这样可以减少内存重分配的次数,提高性能。\[1\] SDS的空间分配策略可以杜绝缓冲区溢出的可能性。在执行修改操作之前,API会先检查SDS的空间是否满足修改所需的需求,如果不满足,则会自动将SDS的空间扩展至所需的大小,然后再执行实际的修改操作,并同时分配未使用的空间。这样可以确保SDS不会出现缓冲区溢出问题。\[2\] 总结来说,RedisSDS使用空间预分配策略来优化字符串的增长操作,并通过检查和自动扩展空间来避免缓冲区溢出问题。这些策略可以提高Redis的性能和安全性。 #### 引用[.reference_title] - *1* [RedisSDS](https://blog.csdn.net/sssxlxwbwz/article/details/123064278)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Redis底层数据结构-SDS](https://blog.csdn.net/weixin_45275107/article/details/126037496)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [redis SDS介绍](https://blog.csdn.net/Mr_Z2017512/article/details/122232918)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值