Redis没有使用C语言字符串的形式,通过’ ’作为结尾,而是使用了简单动态字符串(simple dynamic string)。
当Redis使用的字符串不需要修改字符串的内容的时候,可以使用C语言提供的字符串,当需要修改内容的时候就使用的是简单动态字符串。Redis键值对的操作中,都是使用的简单动态字符串的方式。
这里可以把简单动态字符串理解成一个对象,这个对象的底层保存着一个字符串。
在sds.h/sdshdr结构体中定义了SDS的值
struct sdshdr {int len;int free;char buf[];
};
如果我们使用SDS定义一个SDS内容为“Redis”的对象,则组织结构如下图所示
C字符串获取字符串长度需要遍历,耗时。
SDS记录了长度,可以在O(1)的时间复杂度获取字符串长度。
在C语言中使用strcat(dest, src)的时候,用户自身需要保证dest的空间要大于拼接之后的内存空间。但是很多时候由于疏忽导致内存溢出。SDS解决了这个问题,使用SDS的APIsdscat的时候,他会进行检测空间大小是否能够满足拼接之后的字符串大小。如果不能,他会重新开辟一个拼接后的大度的二倍的字符串空间。
C语言中,使用strcat的时候,用户需要手动开辟空间,然后使用函数进行字符串的拼接。频繁的申请空间是一个耗时的操作。但是Redis是一个数据库,很可能会有频繁的改变数据的操作,所以Redis不能容忍这种问题的出现,于是SDS的结构体中,哟一个free的属性,这个是用来记录未使用的空间的,实现了空间的预分配和惰性空间释放两种优化策略。
空间预分配
当使用SDS的一个API的时候,程序不仅会开辟足够容纳数据的空间,还会额外的开辟未使用的空间。
额外的未使用的空间的开辟,由如下的方式进行决定:
如果程序需要使用的SDS的len长度小于1M的话,程序会开辟和len长度一样大小的free空间。
如果修改之后的len长度大于1M的话,程序会分配free为1M的空间。
另外上面的两种方式还会多分配一个自己的空间,用于存放’ ’。
补充一点:只要当需要扩充内存空间的时候,才需要开辟。
惰性空间释放
当SDS需要使用API去释放空间的时候,这个时候原有字符串会修改,但是开辟的空间并没有释放掉,而是将字符串向前移动,用free记录未使用的空间大小。
SDS底层通过二进制的方式来保存数据。
Redis不仅可以保存文本数据,还可以保存二进制数据。
即使是文本数据,也是转化成二进制数据保存的。
虽然是通过二进制保存数据,但是为了能够兼容string的使用,保存了字符串的一些特性。
SDS主要的API如下表
函数 | 作用 | 时间复杂度 |
---|---|---|
sdsnew | 创建一个包含C字符串的SDS | O(N),N为给定的字符串的长度 |
sdsempty | 创建一个不包含任何内容的空SDS | O(1) |
sdsfree | 释放给定的SDS | O(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 个字节) 〔计算机存储数据分为三个空间:寄存器、栈空间、堆空间。...