redis 简单动态字符串 SDS

redis 没有直接使用c语言传统的字符串表示,而是自己构建了简单动态字符串(SDS)的抽象类型,并将SDS用作redis的默认字符串表示

redis的数据库里面,包含字符串值的键值对在底层都是SDS实现的

执行 rpush fruits "apple" "banana" "pits"

那么redis将在数据库中创建一个新的键值对,其中:

1、键值对的键是一个字符串对象,对象的底层实现是一个保存了字符串的fruits的SDS

2、键值对的值是一个列表对象,列表对象包含了三个字符串对象,这三个字符串对象分别由撒呢SDS实现

SDS结构:

free属性:表示这个SDS没有分配任何未使用的空间

len:保存字符串的长度

buf:字符串的值是一个char类型的数组,最后一个字符串则保存了空字符串‘\0‘

SDS遵循c字符串以空字符串结尾的惯例,保存空字符的1字节空间不计算在SDS的len属性里,并且为空字符串分配额外的1字节空间

为啥遵循空字符串结尾的惯例呢?

因为SDS可以只用重用一部分C字符串函数库中的函数

SDS比C字符串更适用redis的原因是啥呢?

1、因为c字符不记录自身的长度,所以要获取长度,必须遍历整个字符串,而对于SDS来说,设置和更新SDS长度的工作是由SDS的API在执行时自动完成,使用SDS无须进行任何手动修改长度的工作,这确保了redis获取字符串长度工作不会成为redis的性能瓶颈

2、c字符串因为不记录自身长度带来的另一个问题是易造成缓冲区溢出,与c字符串不同的是,SDS的空间分配策略完全杜绝了发生缓冲区溢出的可能性,当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行时机的修改操作,使用使用SDS既不需要手动修改SDS的空间大小,也不会出现前面所说的缓冲区溢出问题。

3、c字符串在修改时比如ajppend操作,如果程序忘记通过内存重分配来扩展底层数组的空间大小就会产生缓冲区溢出。如果进行缩短字符串操作,比如trim,如果程序忘记通过内存重分配来释放字符串不再使用的部分,就会产品内存泄露,为了解决这两个问题,SDS通过未使用空间解除了字符串长度和底层数组长度之间的管理,通过未使用空间,SDS实现了空间预分配和惰性空间释放两种优化策略。

详细说一下这两种优化策略

空间预分配:用于优化SDS的字符串增长操作,当SDS的api对一个sds进行修改,并且需求对sds进行空间扩展的时候,程序不仅会未sds分配修改锁必须要的空间,还会为sdd分配额外的未使用空间,其中公式是:

如果对sds进行修改之后,sds的长度<1MB,那么程序分配和len属性同样大小的未使用空间

如果对sds进行修改好,sds的长度>=1MB,那么程序会分配1MB的未使用空间

使用空间预分配策略,redis可以减少连续执行字符串操作所需的内存重分配次数

惰性空间释放:用户优化sds的字符串缩短的操作,通过惰性空间释放策略,sds避免了缩短字符串时所需要的内存重分配操作,并为将来可能有的增长操作提供了优化。

以上就是SDs比c字符串更使用redis的原因。

为了确保redis可以适用于各种不同的使用场景,sds的api都是二进制安全的,所有的SDs API都会以处理二进制的方式来处理SDS存放在buf数组中数据

通过使用二进制安全的SDS,而不是C字符串,使得redis不仅可以保存文本数据还可以保存任意格式的二进制数据。

重点回顾

1、redis只会使用c字符串最为字面量,在大多数情况下,redis使用sds作为字符串的表示

2、比如c字符串,sds更具有以下优点

1)常数负责度获取字符串长度

2)杜绝缓冲区溢出

3)减少修改字符串长度时所需要的内存重分配次数

4)二进制安全

5)兼容部分c字符函数

之前被问 redis string最大长度 接下来将着重看redis底层 加油

原文地址:https://www.cnblogs.com/weiluoyan/p/9026140.html

时间: 2024-11-07 13:38:53

redis 简单动态字符串 SDS的相关文章

Redis底层探秘(一):简单动态字符串(SDS)

redis是我们使用非常多的一种缓存技术,他的性能极高,读的速度是110000次/s,写的速度是81000次/s.这么高的性能背后,到底是怎么样的实现在支撑,这个系列的文章,我们一起去看看. redis的底层数据结构有以下7种,包括简单动态字符串(SDS),链表.字典.跳跃表.整数集合.压缩列表.对象.今天我们一起看下简单动态字符串(simple dynamic string),后面的文章以SDS简称. SDS简介 Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符串数组,以下简称

Redis源码解析01: 简单动态字符串SDS

Redis没有直接使用C字符串(以'\0'结尾的字符数组),而是构建了一种名为简单动态字符串( simple  dynamic  string, SDS)的抽象类型,SDS设计API实现对字符串的各种修改. 1:SDS的定义 在sds.h中,定义了结构体sdshdr表示SDS,其定义如下: struct sdshdr { unsigned int len; unsigned int free; char buf[]; }; len记录SDS保存的字符串的长度(不包括末尾的'\0'):free记录

Redis数据结构之简单动态字符串SDS

Redis的底层数据结构非常多,其中包括SDS.ZipList.SkipList.LinkedList.HashTable.Intset等.如果你对Redis的理解还只停留在get.set的水平的话,是远远不足以应对面试提问的.本文简单介绍了Redis底层最重要的数据结构 - 简单动态字符串(SDS) Redis使用C语言开发,但并没有使用C语言传统的字符串表示(以空字符结尾的字节数组,以下简称C字符串),而是自己构建了一种名为简单动态字符串的(simple dynamic string,SDS

Redis源码阅读笔记(1)——简单动态字符串sds实现原理

首先,sds即simple dynamic string,redis实现这个的时候使用了一个技巧,并且C99将其收录为标准,即柔性数组成员(flexible array member),参考资料见这里.柔性数组成员不占用结构体的空间,只作为一个符号地址存在,而且必须是结构体的最后一个成员.柔性数组成员不仅可以用于字符数组,还可以是元素为其它类型的数组.C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员.柔性数组成员允许结构中包

Redis 数据结构之简单动态字符串SDS

几个概念1:key对象 数据库存储键值对的键,总是一个字符串对象.2:value对象 数据库存储键值对的值,可以是字符串对象,list对象,hash对象,set对象,sorted set对象.     例如:            set msg "hello world" 则redis在数据库中创建一个新的键值对,键和值都是一个字符串对象,底层实现都是一个sds对象.            rpush fruits "apple" "banana&quo

Redis源码阅读一:简单动态字符串SDS

源码阅读基于Redis4.0.9 SDS介绍 redis 127.0.0.1:6379> SET dbname redis OK redis 127.0.0.1:6379> GET dbname "redis" 从上面的例子可以看到,key为dbname的值是一个字符串"redis" Redis源码是用c写成,但并没有使用c的字符串.c的字符串有以下缺点: 没有储存字符串长度的变量,获取长度只能靠遍历字符串 扩容麻烦.没有相应保护,容易造成缓冲区溢出 更

Redis自定义动态字符串(sds)模块(二)

sds模块的具体实现: 1.sdsnewlen 根据参数生成一个sds字符串 1 sds sdsnewlen(const void *init, size_t initlen) 2 { 3 struct sdshdr *sh; 4 //如果初始化的内容为NULL,则生成一个内容只有一个\0的串,但是长度不会变,还是传入的长度.zmalloc和zcalloc的功能一样,这个地方为啥还要调用不同的呢. 5 if (init) { 6 sh = zmalloc(sizeof(struct sdshdr

redis源码阅读——动态字符串sds

redis中动态字符串sds相关的文件为:sds.h与sds.c 一.数据结构 redis中定义了自己的数据类型"sds",用于描述 char*,与一些数据结构 1 typedef char *sds; 2 3 /* Note: sdshdr5 is never used, we just access the flags byte directly. 4 * However is here to document the layout of type 5 SDS strings. *

小白的Redis学习(一)-SDS简单动态字符串

本文为读<Redis设计与实现>的记录.该书以Redis2.9讲解Redis相关内容.请注意版本差异. Redis使用C语言实现,他对C语言中的char类型数据进行封装,构建了一种简单动态字符串(以下简称SDS),该字符串的结构如下 struct sdshdr{ //记录buf数组中已使用字节的数量 //获取字符串的长度时,就是直接返回的这个字段的值 int len; //记录buf数组中未使用字节的数量 int free; //字节数组,用于保存字符串 char buf[]; } SDS遵循