「Redis」字符串
原文链接: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 修改后的新值长度小于 1MB(len
的长度)。那么程序将会分配和 len
同样大小的闲置空间,即 len = free
。buf
数组的实际长度则是 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」字符串的更多相关文章
- 【LOJ】#3095. 「SNOI2019」字符串
LOJ#3095. 「SNOI2019」字符串 如果两个串\(i,j\)比较\(i < j\),如果离\(a_{i}\)最近的不同的数是\(a_{k}\),如果\(j < k\)那么\(i ...
- 「JSOI2015」字符串树
「JSOI2015」字符串树 传送门 显然可以树上差分. 我们对于树上每一条从根出发的路径都开一 棵 \(\text{Trie}\) 树,那么我们就只需要在 \(\text{Trie}\) 树中插入一 ...
- 「Foundation」字符串
一.Foundation框架中一些常用的类 字符串型: NSString:不可变字符串 NSMutableString:可变字符串 集合型: 1)NSArray:OC不可变数组 NSMutableA ...
- 「Python」字符串操作内置函数
目录: capitalize casefold center count encode decode endswith expandtabs find format format_map index ...
- 分享一个网上搜不到的「Redis」实现「聊天回合制」的方案
前言 为什么说网上搜不到,因为关于聊天回合制的方案作者本人快把百度搜秃噜了也没找到,好在最终是公司一个关系不错的大佬帮提供了点思路,最终作者将其完整实现了出来. 分享出来大家可以收藏,万一你哪天也碰到 ...
- 「SNOI2019」字符串
题目 看起来非常一眼啊,我们完全可以\(std::sort\)来解决这歌问题 于是现在的问题转化成了比较函数怎么写 随便画一下就会发现前面的好几位是一样的,后面的好几位也是一样,只需要比较中间的一段子 ...
- 【LOJ】#2278. 「HAOI2017」字符串
题解 好神仙的题啊 感觉转二维平面能想到,算重复情况的方法真想不到啊 通过扒stdcall代码获得的题解QAQQQQ 我们先把\(p_i\)正串反串建出一个AC自动机来 然后我们把s串放在上面跑匹配, ...
- LOJ#2452. 「POI2010」反对称 Antisymmetry
题目描述 对于一个 \(0/1\) 字符串,如果将这个字符串 \(0\) 和 \(1\) 取反后,再将整个串反过来和原串一样,就称作「反对称」字符串.比如 \(00001111\) 和 \(01010 ...
- 「POI2010」反对称 Antisymmetry (manacher算法)
# 2452. 「POI2010」反对称 Antisymmetry [题目描述] 对于一个 $0/1$ 字符串,如果将这个字符串 $0$ 和 $1$ 取反后,再将整个串反过来和原串一样,就称作「反对称 ...
随机推荐
- css动画实现吃豆豆
话不多说,直接上代码:(作为一个初学者写的代码,多么0基础都能看的懂吧.) HTML部分 <!DOCTYPE html> <html lang=en> <head> ...
- 10_Python的函数function
1.函数的概述 1.函数是可以重复执行的语句块且可以重复调用,函数封装了可重复执行的语句提高了语句的可重复性 2.函数的参数和返回值的作用流程图: https://www.processon. ...
- EasyPoi导出Excel
这几天一直在忙工作中的事情,在工作中有一个问题,可能是因为刚开始接触这个EasyPoi,对其也没有太多的理解,在项目中就使用了,有一个需求,是要导出项目中所有的表格,今天就对这个需求进行分析和实现吧; ...
- leetcode刷题-43字符串相乘
题目 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式. 思路 字符串转数字:从字符串第一位开始取,每次取出的值转换为数字 ...
- SpringMVC-08-SpringMVC层编写
SpringMVC层编写 web.xml DispatcherServlet <!--DispatcherServlet--> <servlet> <servlet-na ...
- oracle之分层查询
ORACLE分层查询start with&connect by 分层查询是select 语句的扩展,目的是迅速找出表中列-列的隶属关系. 19.1 树的遍历 ORACLE是一个关系数据库管理系 ...
- 终于有人把MYSQL索引讲清楚了
一什么是索引 索引在MYSQL中也可以称为键,其是存储引擎用于快速查找记录的一种数据结构:这样听起来有点生涩,你可能难以理解:如果给你一本书,你如何能够精确的查找到书中某个章节的具体位置呢?我们肯定是 ...
- vue项目中使用ts(typescript)入门教程
最近项目需要将原vue项目结合ts的使用进行改造,这个后面应该是中大型项目的发展趋势,看到一篇不错的入门教程,结合它并进行了一点拓展记录之.本文从安装到vue组件编写进行了说明,适合入门. 1.引入T ...
- 《Java核心技术卷一》之 泛型
一.引言 在学习集合的时候我们会发现一个问题,将一个对象丢到集合中后,集合并不记住对象的类型,统统都当做Object处理,这样我们取出来再使用时就得强制转换类型,导致代码臃肿,而且加入集合时都是以Ob ...
- Oracle学习(三)SQL高级--表结构相关(建表、约束)
一.建表语句 CREATE DATABASE(创建数据库) --创建数据库 create database 数据库名字; CREATE TABLE(创建表) --创建表 CREATE TABLE 表名 ...