简单动态字符串 sds

news2025/1/19 23:23:45

        Redis 设计了简单动态字符串(Simple Dynamic String,SDS)的结构,用来表示
字符串。相比于 C 语言中的字符串实现,SDS 这种字符串的实现方式,会提升字符串的操
作效率,并且可以用来保存二进制数据

为什么 Redis 不用 char*?

首先得先了解char* 字符串数组的结构特点,还有 Redis对字符串的需求是什么,所以下面我们就来具体分析一下

char* 的结构设计

char*字符数组的结构很简单,就是一块连续的内存空间,依次存放了字符串中的每一个
字符。比如,下图显示的就是字符串“redis”的char*数组结构。、

 从图中可以看到,字符数组的最后一个字符是“\0”,这个字符的作用是什么呢?其实,C
语言在对字符串进行操作时,char* 指针只是指向字符数组的起始位置,而字符数组的结尾
位置就用“\0”表示,意思是指字符串的结束

c语言标准库呢就是检查字符这个字符是不是\0然后不是加一往下走,是的话结束

创建了两个字串变量 a 和 b,分别给它们赋值为“red\0is”和“redis\0”。然后,我用 strlen 函数
计算这两个字符串长度,如下所示:

 当程序执行完这段代码后,输出的结果分别是 3 和 5。

也就是说,char* 字符串以“\0”表示字符串的结束,其实会给我们保存数据带来一定的负
面影响。如果我们要保存的数据中,本身就有“\0”,那么数据在“\0”处就会被截断,
而这就不符合 Redis 希望能保存任意二进制数据的需求了

操作函数复杂度

用char* 会导致复杂度增加

字符串追加函数 strcat 和上边的strlen函数都需要遍历到字符串的末尾


SDS 的设计思想

因为 Redis 是使用 C 语言开发的,所以为了保证能尽量复用 C 标准库中的字符串操作函
数,Redis 保留了使用字符数组来保存实际的数据。但是,和 C 语言仅用字符数组不同,
Redis 还专门设计了 SDS(即简单动态字符串)的数据结构

SDS 结构设计

首先,SDS 结构里包含了一个字符数组 buf[],用来保存实际数据。同时,SDS 结构里还
包含了三个元数据,分别是字符数组现有长度 len、分配给字符数组的空间长度 alloc,以
及 SDS 类型 flags
。其中,Redis 给 len 和 alloc 这两个元数据定义了多种数据类型,进
而可以用来表示不同类型的 SDS

在 Redis 源码中查找过 SDS 的定义,那你可能会看到,Redis 使用 typedef
给 char* 类型定义了一个别名,这个别名就是 sds 

typedef char *sds;

因为 SDS 本质还是字符数组,只是在字符数组基础上增加了额外的元数据。在
Redis 中需要用到字符数组时,就直接使用 sds 这个别名。

在创建新的字符串时,Redis 会调用 SDS 创建函数 sdsnewlen。sdsnewlen 函数
会新建 sds 类型变量(也就是 char* 类型变量),并新建 SDS 结构体,把 SDS 结构体中

的数组 buf[] 赋给 sds 类型变量。最后,sdsnewlen 函数会把要创建的字符串拷贝给 sds
变量。下面的代码就显示了 sdsnewlen 函数的这个操作逻辑,你可以看下

 SDS操作效率

因为它本身的数据结构

紧凑型字符串结构的编程技巧

SDS 结构中有一个元数据 flags,表示的是 SDS 类型

事实上,SDS 一共设计了 5 种类型,分别是 sdshdr5、sdshdr8、sdshdr16、sdshdr32 和 sdshdr64

这 5种类型的主要区别就在于,它们数据结构中的字符数组现有长度 len 和分配空间长度
alloc,这两个元数据的数据类型不同。

因为 sdshdr5 这一类型 Redis 已经不再使用了,主要来了解下剩余的 4 种类
型。以 sdshdr8 为例,它的定义如下所示

 我们可以看到,现有长度 len 和已分配空间 alloc 的数据类型都是 uint8_t。uint8_t 是 8
位无符号整型,会占用 1 字节的内存空间。当字符串类型是 sdshdr8 时,它能表示的字符
数组长度(包括数组最后一位\0)不会超过 256 字节(2 的 8 次方等于 256)。

而对于 sdshdr16、sdshdr32、sdshdr64 三种类型来说,它们的 len 和 alloc 数据类型分
别是 uint16_t、uint32_t、uint64_t,即它们能表示的字符数组长度,分别不超过 2 的 16
次方、32 次方和 64 次方。这两个元数据占用的内存空间在 sdshdr16、sdshdr32、
sdshdr64 类型中,则分别是 2 字节、4 字节和 8 字节。

SDS 之所以设计不同的结构头(即不同类型),是为了能灵活保存不同大小的字
符串,从而有效节省内存空间

除了设计不同类型的结构头,Redis 在编程上还使用了专门的编译优化来节省内存
空间。在刚才介绍的 sdshdr8 结构定义中,我们可以看到,在 struct 和 sdshdr8 之间使
用了__attribute__ ((__packed__)),如下所示:

struct __attribute__ ((__packed__)) sdshdr8

其实这里,__attribute__ ((__packed__))的作用就是告诉编译器,在编译
sdshdr8 结构时,不要使用字节对齐的方式,而是采用紧凑的方式分配内存。这是因为在
默认情况下,编译器会按照 8 字节对齐的方式,给变量分配内存。也就是说,即使一个变
量的大小不到 8 个字节,编译器也会给它分配 8 个字节

到这里呢需要了解一下,字节对齐是为什么?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/843030.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Element-Plus DatePicker获取时间戳

文章目录 0、先上答案1、渔&#xff1f;1-1 Element-Plus 官网1-2 溯源 Day.js 0、先上答案 <!-- 秒 --><el-date-pickerv-model"timeStamp"type"datetime"value-format"X"/><!-- 毫秒 --><el-date-pickerv-model"tim…

Spring Boot 最佳实践

本文翻译自国外论坛 medium&#xff0c;原文地址&#xff1a;https://medium.com/raviyasas/spring-boot-best-practices-for-developers-3f3bdffa0090 Spring Boot 是一种广泛使用且非常流行的企业级高性能框架。以下是一些最佳实践和一些技巧&#xff0c;我们可以使用它们来…

【Git分布式版本控制系统一】你还不会用Git进行项目管理?

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; 前言 众所周知&#xff0c;分布式版本控制系统git是工作以后进行项目管理必不可少的工具&#xff0c;我将繁杂的命令进行了归类整理和总结&#xff0c;供大家参考学习…

springboot+vue真实项目部署详细步骤

sprinbootvue项目详细部署步骤 文章目录 sprinbootvue项目详细部署步骤1、准备部署文件2、安装mysql2.1、配置mysql2.2、用navicat远程连接mysql导入数据2.3、导入mysql数据 3、安装jdk4、安装nginx5、安装redis6、创建对应的目录层级和启动6.1 构建启动脚本6.2 、修改两个后台…

数据库索引的使用

1、MySQL的基本架构 架构图 左边的client可以看成是客户端&#xff0c;客户端有很多&#xff0c;像我们经常你使用的CMD黑窗口&#xff0c;像我们经常用于学习的WorkBench&#xff0c;像企业经常使用的Navicat工具&#xff0c;它们都是一个客户端。右边的这一大堆都可以看成是…

Python系统学习1-5-容器

1、字符串 字符串是不可变的数据 原因&#xff1a;如果在原有内存中修改&#xff0c;很可能破坏其他数据的空间 现象&#xff1a;每次需要修改字符串时&#xff0c;都会创建新数据&#xff0c;替换变量中存储的地址 字符串字面值 (1)建议使用双引号 name01 "悟空&q…

中介者模式(C++)

定义 用一个中介对象来封装(封装变化)一系列的对象交互。中介者使各对象不需要显式的相互引用(编译时依赖->运行时依赖)&#xff0c;从而使其耦合松散(管理变化)&#xff0c;而且可以独立地改变它们之间的交互。 应用场景 在软件构建过程中&#xff0c;经常会出现多个对象…

VUE框架:vue2转vue3全面细节总结(5)过渡动效

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

公文写作素材:“干”字型排比句40例

1.怀着真诚“想干”&#xff0c;扛着担当“敢干”&#xff0c;瞄着路径“能干”&#xff0c;盯着责任“真干”&#xff0c;想着办法“会干”&#xff0c;带着智慧“巧干”&#xff0c;揣着情怀“认干”&#xff0c;铆着劲头“实干”。 2.脱下“皮鞋”、换上“运动鞋”&#xff…

3 vue的if语法

vue的if语法是相当于一个标签的属性来写进去的&#xff0c;比如说<h1 v-if“”>。要注意的是if语句里可以自动从数据层取值的&#xff0c;比如<h1 v-if"message">&#xff0c;这里就会自动把key为message的值取过来&#xff0c;而如果要传一个字符串&…

Vue [Day5]

自定义指令 全局注册 和 局部注册 inserted在指令所在的元素 被插入到页面中时&#xff0c;触发 main.js import Vue from vue import App from ./App.vueVue.config.productionTip false// 1.全局注册指令 Vue.directive(focus, {// inserted在指令所在的元素 被插入到页…

Java个人博客系统--基于Springboot的设计与实现

目录 一、项目概述 应用技术 接口实现&#xff1a; 数据库定义&#xff1a; 数据库建表&#xff1a; 博客表数据库相关操作&#xff1a; 添加项⽬公共模块 加密MD5 页面展示&#xff1a;http://121.41.168.121:8080/blog_login.html 项目源码&#xff1a;https://gitee…

初学 Python 需要安装哪些软件?超级实用,小白必看!

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 编程这个东西是真的奇妙。 对于懂得的人来说&#xff0c;会觉得这个工具是多么的好用、有趣&#xff0c;而对于小白来说&#xff0c;就如同大山一样。 其实这个都可以理解&#xff0c;大家都是这样过来的。 那么接下来就说…

Spring简述

Sping是什么Spring主要模块IOCDI依赖注入的三种方式 AOP术语 Sping是什么 Spring是一个轻量级的开源框架&#xff0c;主要作用是为了简化开发&#xff0c;它以IOC&#xff08;控制反转&#xff09;和AOP&#xff08;面向切面编程&#xff09;为内核 Spring主要模块 我们一般…

cocosCreator 之 i18n多语言插件

版本&#xff1a; v3.4.0 环境&#xff1a; Mac 简介 i18n是国际化的简称&#xff0c; 全名&#xff1a;internationalization&#xff1b;取首尾字符i和n&#xff0c;18代表单词中间的字符数目。 该插件不需要产品做太多的改变&#xff0c;通过语言的设置&#xff0c;实现不…

P1194 买礼物(最小生成树)(内附封面)

买礼物 题目描述 又到了一年一度的明明生日了&#xff0c;明明想要买 B B B 样东西&#xff0c;巧的是&#xff0c;这 B B B 样东西价格都是 A A A 元。 但是&#xff0c;商店老板说最近有促销活动&#xff0c;也就是&#xff1a; 如果你买了第 I I I 样东西&#xff0…

【逗老师的PMP学习笔记】6、项目的进度管理

目录 一、规划进度管理1、【关键输出 】进度管理计划 二、定义活动1、【关键工具】拆解2、【关键工具】滚动式规划3、【关键输出】活动清单和活动属性4、【关键输出】里程碑清单 三、排列活动顺序1、【关键工具】紧前关系绘图法2、【关键工具】提前量和滞后量3、【关键输出】项…

Linux 中使用 verdaccio 搭建私有npm 服务器

安装 Node Linux中安装Node 安装verdaccio npm i -g verdaccio安装完成 输入verdaccio,出现下面信息代表安装成功&#xff0c;同时输入verdaccio后verdaccio已经处于运行状态&#xff0c;当然这种启动时暂时的&#xff0c;我们需要通过pm2让verdaccio服务常驻 ygiZ2zec61wsg…

网络编程——深入理解TCP/IP协议——OSI模型和TCP/IP模型:构建网络通信的基石

TCP/IP协议— 一、简介 TCP/IP协议&#xff0c;即传输控制协议/互联网协议&#xff0c;是一组用于在计算机网络中实现通信的协议。它由两个主要的协议组成&#xff1a;TCP&#xff08;传输控制协议&#xff09;和IP&#xff08;互联网协议&#xff09;。TCP负责确保数据的可靠…

【Linux取经路】冯诺依曼结构体系与操作系统的碰撞

文章目录 一、冯诺依曼体系结构1.1 硬件介绍1.2 内存的重要性 二、操作系统2.1 设计操作系统的目的2.2 操作系统是如何进行管理的&#xff1f; 一、冯诺依曼体系结构 我们现在常见的计算机&#xff0c;如笔记本&#xff0c;以及我们不常见的计算机&#xff0c;如服务器&#x…