理解Redis SDS(简单动态字符串)

2024-01-19 22:38

本文主要是介绍理解Redis SDS(简单动态字符串),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简述

Redis中并没有直接使用C语言的字符串表示(在内存中以“\0”作为字符串的结尾),而是自己新建了一个字符串的结构,该结构就是SDS(Simple Dynamic String,简单动态字符串)。

SDS在Redis中的使用

Redis中设计可变字符串都是用的SDS结构,如Redis底层为键值对结构,所有的键都是字符串类型的,就是SDS结构的对象。当然Redis打印日志时,字符串不需要变化,则是使用的C语言的字符串。

SDS结构

struct sdshdr{//buf数组中未使用的字节数量int free;//buf数组中已经使用的字节数量,不包括“\0”int len;//字节数组,用来保存字符串char buf[];
}

假如用SDS来存储字符串“Redis”,那么其结构如下:
在这里插入图片描述
len为5,实际buf数组的长度为6,有一个字节用来存储了“\0”。SDS不需要“\0”来判断字符串是否到结尾,那么为什么还要在buf数组最后用“\0”作为结尾呢?其实主要是Redis还要用到C语言中对字符串的处理函数,以“\0”作为结尾,Redis就可以使用这些函数而不用自己去实现。

SDS与C语言字符串的区别

获取字符串长度时时间复杂度O(1)

在C语言的字符串中,以"\0"作为结尾,在需要求字符串长度的时候,需要遍历数组到“\0”处,时间复杂度为O(N)。而在SDS的结构中,可以直接从len中读取长度,时间复杂度为O(1)。

缓冲区溢出问题

传统C语言字符串在执行诸如字符串相加的函数时,是假设使用者已经进行了内存的分配,有足够的内存可以供操作,假如使用者在执行函数之前没有进行内存处理,就可能出现缓冲区溢出的情况。
如:现在有两个字符串S1,S2,结构如下:
在这里插入图片描述
此时,如果直接给S1加上“ Cluster”,就会发生溢出,结构变为:
在这里插入图片描述
可以看到S2的字符串变为“Cluster”。而SDS结构中free字段,明确规定了buf数组空闲字节的数量,执行操作之前可以计算free是否足够放下新的字符串,如果不够就进行内存分配,这样就可以防止缓冲区溢出。

减少内存分配的次数

传统的C语言字符串,在进行字符串相加操作之前,每一次操作都需要进行内存分配,防止缓冲区溢出。而SDS,如果free空闲字节数量足够,完全可以直接进行操作,不需要进行空间申请。那么SDS是怎么判断应该预留多少free的呢?

空间预分配

假如free中空闲的字节数不足以放下新的字符串,那么SDS也会申请进行内存分配,保证buf足够的空间放下新的字符串。当存储的字符串大小小于1MB时,free会和len一样大,也就是假设新的字符串大小len为13,那么free也为13,buf数组的长度为13 + 13 + 1(\0占一位)。如果新的字符串超过1MB,那么free就为1MB。

惰性释放内存空间

buf存储的字符串进行缩减操作时,内存空间并不会立刻释放,释放出来的字节数目会加到free中。

二进制安全

传统的C语音字符串是无法保存媒体数据的,因为如果数据中有“\0”就会被判断为结尾。使用SDS就可以存储媒体数据。

注:"\0"是 ASCII 码为 0 的字符,对应的字符是(Null),C语言中用来判断字符串的结尾

这篇关于理解Redis SDS(简单动态字符串)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/623924

相关文章

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

redis群集简单部署过程

《redis群集简单部署过程》文章介绍了Redis,一个高性能的键值存储系统,其支持多种数据结构和命令,它还讨论了Redis的服务器端架构、数据存储和获取、协议和命令、高可用性方案、缓存机制以及监控和... 目录Redis介绍1. 基本概念2. 服务器端3. 存储和获取数据4. 协议和命令5. 高可用性6.

Redis的数据过期策略和数据淘汰策略

《Redis的数据过期策略和数据淘汰策略》本文主要介绍了Redis的数据过期策略和数据淘汰策略,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录一、数据过期策略1、惰性删除2、定期删除二、数据淘汰策略1、数据淘汰策略概念2、8种数据淘汰策略

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

Redis存储的列表分页和检索的实现方法

《Redis存储的列表分页和检索的实现方法》在Redis中,列表(List)是一种有序的数据结构,通常用于存储一系列元素,由于列表是有序的,可以通过索引来访问元素,因此可以很方便地实现分页和检索功能,... 目录一、Redis 列表的基本操作二、分页实现三、检索实现3.1 方法 1:客户端过滤3.2 方法

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

Python中操作Redis的常用方法小结

《Python中操作Redis的常用方法小结》这篇文章主要为大家详细介绍了Python中操作Redis的常用方法,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解一下... 目录安装Redis开启、关闭Redisredis数据结构redis-cli操作安装redis-py数据库连接和释放增