原文链接:https://www.changxuan.top/?p=1109

简介

Redis 中自定义的字符串结构。

字符串是 Redis 中最常用的一种数据类型,在 Redis 中专门封装了一个字符串结构体——简单动态字符串(Simple Dynamic String, SDS)。其结构体如下:

struct sdshdr {
    // 记录 buf 数组中已使用字节的数量既 SDS 中所保存字符串的长度
    int len;
    // 记录 buf 数组中未使用字节的数量
    int free;
    // 字节数组,用于保存字符串。
    char buf[];
}

len 的值为 8 时,表示在 buf 数组中保存了一个 8 字节长的字符串;当 free 的值为 2 时,表示在 buf 数组中还有两个字节的空间未使用。如果为 0 ,则表示当前 buf 数组的空间已经全部分配完毕;buf 则是一个 char 类型的数组。SDS 遵循了C字符串以空字符结尾的惯例,即存储在 buf 中的字符串末尾都会紧跟一个空字符 \0 ,这个空字符对于用户来说是透明的,它并不会被计入 len 中。

优点

为什么要在 Redis 中要自定义字符串的数据结构?

1 时间复杂度

首先,由上面代码我们可以知道通过 SDS 获取字符串的长度的时间复杂度为 O(1)。而如果使用 C 字符串每次获取字符串长度时的时间复杂度则为 O(N)。即当我们使用 STRLEN 命令获取某个键值的长度时不用担心性能问题。

2 缓冲区溢出

其次,可以避免缓冲区溢出问题。例如,两个C字符串在内存中紧挨着,如果没有提前给前一个字符串分配足够空间的情况下就使用 strcat 函数在其末尾追加新的字符串。那么新拼接的字符串就会溢出到后一个字符串的空间中,从而导致后一个字符串的内容发生改变。但是在 SDS 中,对内容进行修改之前会先检查其内存空间是否满足要求,如果不满足要求,则会自动将空间扩展至所需要的大小。扩展空间大小的操作对于用户来说也是透明的。

另外,为了避免可能由于频繁的修改字符串内容,而导致产生较为耗时的内存重分配问题。SDS 通过以空间换时间的方式即未使用空间来尽量避免这种问题。在 SDS中实现了空间预分配惰性空间释放两种优化策略。

优化策略

空间预分配

当 SDS 中的字符串变长时,程序先判断当前闲置空间是否满足需求。如果不满足,则按照空间预分配的策略对空间进行扩展。Redis 不仅仅只分配所需要的空间大小,则是根据规则多分配一些空间。当 SDS 修改后的新值长度小于 1MBlen 的长度)。那么程序将会分配和 len 同样大小的闲置空间,即 len = freebuf 数组的实际长度则是 len + free + 1 字节。如果修改后的新值大于等于 1MB,程序则会分配 1MB 的未使用空间。

如此一来,就不需要每次增加字符串长度时必须对内存重新分配,从而提高了系统性能。

惰性空间释放

当 SDS 中的字符串变短时,程序并不是直接进行内存重分配回收多余的空间,而是使用 free 记录下来。如果将来再变长时,可以直接使用。

通过惰性空间释放,避免了缩短字符串时产生的内存重分配操作。

3 二进制安全

由于C字符串的特殊性,在一些场景中会出现问题。如,一个字符串中存在多个空字符,那么C字符串只能识别出第一个空字符之前的内容。且C字符串只能保存文本数据。

而 SDS 的 API 都是二进制安全的,所有的 API 都会以处理二进制的方式来处理 SDS 存放在 buf 数组中的数据,以保证数据写入前与读取后的一致性。

4 兼容部分C字符串函数

避免了重复造轮子的问题。

SDS API

函数 作用 备注
sdsnew 创建一个包含给定 C 字符串的 SDS
sdsempty 创建一个不包含任何内容的空 SDS
sdsfree 释放给定的 SDS
sdslen 返回 SDS 已使用的空间字节数
sdsavail 返回SDS 未使用的空间字节数
sdsdump 创建一个给定 SDS 的副本
sdsclear 清空 SDS 保存的字符串内容
sdscat 将给定的C字符串拼接到 SDS字符串末尾
sdscatsds 将给定的SDS字符串拼接到另一个SDS字符串的末尾
sdscpy 将给定的C字符串复制到 SDS中,并覆盖SDS中原有的字符串
sdsgrowzero 用空字符将SDS扩展至给定长度
sdsrange 保留SDS给定区间内的数据
sdstrim 接受一个 SDS 和一个 C字符串作为参数,从 SDS 中移除所有在C字符串中出现过的字符
sdscmp 对比两个 SDS 是否相同

「Redis」字符串的更多相关文章

  1. 【LOJ】#3095. 「SNOI2019」字符串

    LOJ#3095. 「SNOI2019」字符串 如果两个串\(i,j\)比较\(i < j\),如果离\(a_{i}\)最近的不同的数是\(a_{k}\),如果\(j < k\)那么\(i ...

  2. 「JSOI2015」字符串树

    「JSOI2015」字符串树 传送门 显然可以树上差分. 我们对于树上每一条从根出发的路径都开一 棵 \(\text{Trie}\) 树,那么我们就只需要在 \(\text{Trie}\) 树中插入一 ...

  3. 「Foundation」字符串

    一.Foundation框架中一些常用的类 字符串型: NSString:不可变字符串 NSMutableString:可变字符串 集合型: 1)NSArray:OC不可变数组  NSMutableA ...

  4. 「Python」字符串操作内置函数

    目录: capitalize casefold center count encode decode endswith expandtabs find format format_map index ...

  5. 分享一个网上搜不到的「Redis」实现「聊天回合制」的方案

    前言 为什么说网上搜不到,因为关于聊天回合制的方案作者本人快把百度搜秃噜了也没找到,好在最终是公司一个关系不错的大佬帮提供了点思路,最终作者将其完整实现了出来. 分享出来大家可以收藏,万一你哪天也碰到 ...

  6. 「SNOI2019」字符串

    题目 看起来非常一眼啊,我们完全可以\(std::sort\)来解决这歌问题 于是现在的问题转化成了比较函数怎么写 随便画一下就会发现前面的好几位是一样的,后面的好几位也是一样,只需要比较中间的一段子 ...

  7. 【LOJ】#2278. 「HAOI2017」字符串

    题解 好神仙的题啊 感觉转二维平面能想到,算重复情况的方法真想不到啊 通过扒stdcall代码获得的题解QAQQQQ 我们先把\(p_i\)正串反串建出一个AC自动机来 然后我们把s串放在上面跑匹配, ...

  8. LOJ#2452. 「POI2010」反对称 Antisymmetry

    题目描述 对于一个 \(0/1\) 字符串,如果将这个字符串 \(0\) 和 \(1\) 取反后,再将整个串反过来和原串一样,就称作「反对称」字符串.比如 \(00001111\) 和 \(01010 ...

  9. 「POI2010」反对称 Antisymmetry (manacher算法)

    # 2452. 「POI2010」反对称 Antisymmetry [题目描述] 对于一个 $0/1$ 字符串,如果将这个字符串 $0$ 和 $1$ 取反后,再将整个串反过来和原串一样,就称作「反对称 ...

随机推荐

  1. django学习(二)

    1.反向解析 什么是方向解析呢? 通过一些方法得到一个结果,该结果可以直接访问对应url出发视图函数. 先给一个路由和视图函数起一个别名.但是我们要注意的是反向解析的别名是不可以冲突的!!!不然会出现 ...

  2. Building(单调栈+凸包)

    Problem Description Once upon a time Matt went to a small town. The town was so small and narrow tha ...

  3. Oracle 回滚段undo

    Undo的作用 数据的回滚 一致性读 表的闪回(事务,查询的闪回..) 失败会话的恢复 回滚rollback操作 SQL> archive log list; ORA-01031: 权限不足 S ...

  4. 19_Python算法

    1.冒泡算法 list = [1, 5, 2, 6, 9, 3, 4, 0] print(len(list)) # conunt = 1 while conunt < len(list): fo ...

  5. apply用法

    result.push.apply(result, document.getElementsByTagName(tag)); 但是,这里为什么要用apply呢? 因为document.getEleme ...

  6. postman测试接口

    一.postman安装 不介绍.可百度搜索.安装完成后如下: 二.postman测试接口 get请求: post请求:请求参数如果是json格式,则如下 上传文件:如果接口中要求上传文件,可如下操作 ...

  7. Appium之启动第一个App

    搭建appium自动化环境真是各种问题呀. 如何启动在真机上启动App? 执行操作:操作Android真机上打开手机淘宝app,并搜索“熊猫”. 脚本源码如下: from appium import ...

  8. linux下清空文件内容的3个命令

    1.使用echo "" > file_name,直接将空字符串重定向并覆盖到目标文件 2.使用cat /dev/null > file_name,读取dev目录下的一个 ...

  9. python之Lambda

    Python 匿名函数lambda   lambda表达式在“:”后只能有一个表达式.也就是说,在def中,用return可以返回的也可以放在lambda后面,不能用return返回的也不能定义在py ...

  10. 第16课 - make的隐式规则(下)

    第16课 - make的隐式规则(下) 1