首页 > redis学习 -- 简单动态字符串

redis学习 -- 简单动态字符串

Redis没有使用C语言字符串的形式,通过’’作为结尾,而是使用了简单动态字符串(simple dynamic string)。

当Redis使用的字符串不需要修改字符串的内容的时候,可以使用C语言提供的字符串,当需要修改内容的时候就使用的是简单动态字符串。Redis键值对的操作中,都是使用的简单动态字符串的方式。

这里可以把简单动态字符串理解成一个对象,这个对象的底层保存着一个字符串。

SDS定义

在sds.h/sdshdr结构体中定义了SDS的值

struct sdshdr {int len;int free;char buf[];
};

如果我们使用SDS定义一个SDS内容为“Redis”的对象,则组织结构如下图所示

在这里插入图片描述

  • free属性值为0,表示这个SDS没有分配任何没有使用的空间。
  • len属性的值是5,表示这个SDS保存了一个五字节长的字符串。
  • buf属性是一个char类型的数组,数组里面保存了字符串的值,并且以’’结束。

SDS和C字符串的区别和优势

常数时间复杂度获取字符串长度

C字符串获取字符串长度需要遍历,耗时。

SDS记录了长度,可以在O(1)的时间复杂度获取字符串长度。

杜绝缓冲区溢出

在C语言中使用strcat(dest, src)的时候,用户自身需要保证dest的空间要大于拼接之后的内存空间。但是很多时候由于疏忽导致内存溢出。SDS解决了这个问题,使用SDS的APIsdscat的时候,他会进行检测空间大小是否能够满足拼接之后的字符串大小。如果不能,他会重新开辟一个拼接后的大度的二倍的字符串空间。

减少修改字符串时带来的内存重分配次数

C语言中,使用strcat的时候,用户需要手动开辟空间,然后使用函数进行字符串的拼接。频繁的申请空间是一个耗时的操作。但是Redis是一个数据库,很可能会有频繁的改变数据的操作,所以Redis不能容忍这种问题的出现,于是SDS的结构体中,哟一个free的属性,这个是用来记录未使用的空间的,实现了空间的预分配和惰性空间释放两种优化策略。

  1. 空间预分配

    当使用SDS的一个API的时候,程序不仅会开辟足够容纳数据的空间,还会额外的开辟未使用的空间。

    额外的未使用的空间的开辟,由如下的方式进行决定:

    如果程序需要使用的SDS的len长度小于1M的话,程序会开辟和len长度一样大小的free空间。

    如果修改之后的len长度大于1M的话,程序会分配free为1M的空间。

    另外上面的两种方式还会多分配一个自己的空间,用于存放’’。

    补充一点:只要当需要扩充内存空间的时候,才需要开辟。

  2. 惰性空间释放

    当SDS需要使用API去释放空间的时候,这个时候原有字符串会修改,但是开辟的空间并没有释放掉,而是将字符串向前移动,用free记录未使用的空间大小。

二进制安全

SDS底层通过二进制的方式来保存数据。

Redis不仅可以保存文本数据,还可以保存二进制数据。

即使是文本数据,也是转化成二进制数据保存的。

兼容部分C字符串函数

虽然是通过二进制保存数据,但是为了能够兼容string的使用,保存了字符串的一些特性。

SDS API

SDS主要的API如下表

函数作用时间复杂度
sdsnew创建一个包含C字符串的SDSO(N),N为给定的字符串的长度
sdsempty创建一个不包含任何内容的空SDSO(1)
sdsfree释放给定的SDSO(N),N为被释放的SDS的长度
sdslen返回SDS的已经使用空间字节数O(1),通过读取对象的len值直接获取
sdsavail返回SDS未使用的空间字节数O(1),通过读取对象的free的值获取
sdsdup创建一个SDS的副本O,N是给定的SDS的长度
stdclear清空SDS保存的字符串内容O(1),由于惰性空间释放,只改变了对象的len值
stscat将给定C字符串拼接都SDS字符串的末尾O(N),N为被拼接的字符串的长度
sdscatsds将给定的SDS拼接到另一个SDS字符串的末尾O,N为被拼接的SDS字符串的长度
sdscpy将给定的C字符串复制到SDS里面,覆盖原有的字符串O(N),N为被复制的C字符串的长度
sdsgrowzero用空字符串将SDS扩展到给定长度O(N),N为扩展新增的字节数
sdssrange保留SDS给定区间的数据,不再全进的数据会被覆盖或者是清除O(N),N为被保留数据的字节数
sdstrin接受一个SDS和一个C字符串作为参数,从SDS左右两端移除所有在C字符串中出现过的字符串O(M*N),M为SDS的长度,N为给定C字符串的长度
sdscmp对比两个SDS字符串是否相同O(N),N为两个SDS中较短的那个SDS的长度

更多相关:

  • 运算符一.算数运算:二.比较运算:三.赋值运算四.逻辑运算 五.成员运算基本数据类型一.Number(数字)Python3中支持int、float、bool、complex。使用内置的type()函数查询变量类型。int(整型)在python2中整数类型有两种一个是int,表示整型,一种是long,表示长整型。而在python3中整数...

  • 题目:面试题38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列。 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。 示例: 输入:s = "abc" 输出:["abc","acb","bac","bca","cab","cba"] 限制: 1 <= s 的长度 <= 8 解题: clas...

  •      给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。 示例 1: 输入: "()" 输出: true 示例 2: 输入: "()[]{}" 输出:...

  • 设计思路:导入Scanner类输入字符串,再将输入的字符串转化为字符数组,然后从字符串左右两侧依次比较字符chu是否相同,若相同递归返回读取的字符个数,若返回字符的个数==输入字符串的长度,则输出该字符串是回文,否则输 出该字符串不是回文   import java.util.Scanner;public class test1...

  • 强化学习(六) - 连续空间中的强化学习6.1 连续空间中的强化学习6.2 离散空间和连续空间6.3 离散化实例:小车上山6.3.1 相关程序6.3.2 程序注解(1) 环境测试(2) 离散化(3) 模型训练(4) 模型优化...

  • JavaScript 的命名空间并不是真正的命名空间, 只是在脚本内部创建一个封闭的小空间, 必须通过特定的空间名称才能对空间内部的代码进行访问, 这样可以防止同名函数和变量发生冲突, 也可以更方便地管理代码, 就像 .NET 的命名空间 (namespace) 和 Java 的包 (package) 一样. 为什么需要命名空间...

  • 线元决定空间,通过定义时空线元,获得闵氏空间:     转载于:https://www.cnblogs.com/YouXiangLiThon/p/9907552.html...

  • sql数据库系统表,常用的(sysobjects,sysindexes,sysindexkeys,SYSCOLUMNS,SYSTYPES 及更多解释说明): https://docs.microsoft.com/zh-tw/previous-versions/sql/sql-server-2012/ms177596(v%3dsql....

  • ----------siwuxie095             1、概述 2、栈空间 3、堆空间          1、概述            (布尔类型如果作为单个变量存储数据将占用 4 个字节,如果作为数组中的某个元素只占用 1 个字节)                〔计算机存储数据分为三个空间:寄存器、栈空间、堆空间。...