Redis设计与实现 (一): 简单动态字符串
1.定义
Redis没有使用C语言的字符串, C语言的字符串只会用在不需要对字符串修改而只使用其值地方. Redis使用SDS表示字符串, 结构定义 :
typedef char *sds;
struct sdshdr {
// 记录 buf 数组中已使用字节的数量
// 等于 SDS 所保存字符串的长度
int len;
// 记录 buf 数组中未使用字节的数量
int free;
// 字节数组,用于保存字符串
char buf[];
};
SDS也是以'\0'表示结束, 这一个字节不会计入已使用的长度. 这样做的好处是可以重用C字符串函数库里面的一部分函数.
2.SSD和C字符串的区别
C语言使用长度为N+1的数组表示长度为N的字符串, 最后一个元素总是空字符'\0', 这种方式不能满足Redis对字符串效率, 安全性, 以及功能方面的要求. 下面介绍SDS比C语言字符串的更加适用Redis的原因.
2.1 常数时间获取字符串长度
C字符串需要遍历, 时间复杂度为O(n).
SDS直接获取, 时间复杂度为O(1).
2.2防止缓冲区溢出
C语言不记录自身长度, 容易造成缓冲区溢出,. 例如内存中有两个相邻字符串是s1 和 s2 . s1长度为5个字节, s2长度为5个字节. 这时如果想要在s1后面添加一个字符串s3, 长度为5个字节, 执行
strcat(s1, s3)
但是忘记给s1分配足够的内存空间, s1的数据就会溢出到s2的空间, 导致s2的内容被修改.
SDS的空间分配策略完全杜绝了这种可能性. 当API需要对SDS进行修改时, API会首先会检查SDS的空间是否满足条件, 如果不满足, API会自动对它动态扩展, 然后再进行修改, 这个过程是完全透明的.
2.3减少修改字符串带来的内存重分配次数
C语言对字符串修改后都需要手动重新分配内存; 当增加长度时需要扩展内存, 否则会产生缓冲区溢出; 当缩小长度时需要释放内存, 否则会产生内存泄露.
由于Redis频繁操作数据, 内存分配和释放耗时可能对性能造成影响, SSD避免了这种缺陷, 实现空间预分配和惰性空间释放两种优化策略
空间预分配
如果修改后len长度将小于 1 M, 这时分配给free的大小和len一样, 例如修改过后为13字节, 那么给free也是13字节 . buf实际长度变成了 13 byte+ 13byte + 1byte = 27byte
如果修改后len长度将大于等于1 M, 这时分配给free的长度为 1 M, 例如修改过后为30M, 那么给free是1M . buf实际长度变成了 30M + 1M + 1 byte
在修改时, 首先检查空间是不是够, 如果足够, 直接使用, 否则执行内存重分配.
惰性空间释放
当缩短SDS长度时, 不进行内存释放, 而是记录到free字段中, 等待下次使用. 与此同时, 也提供相应的API, 可以手动释放内存.
2.4 二进制安全
C字符串只有末尾能保存空格, 中间如果有空格会被截取, 认作结束标识. 这样就不能保存图片, 音频视频等二进制数据了.
所有的SDS API会以二进制的方式处理SDS buf数组里面的数据, 程序不会对其中数据做任何限制, 过滤,修改和假设, 数据写入是什么样子, 读取出来就是什么样子.
例如 : 保留的数据中间出现'\0', 这是没有任何问题的. , 因为它使用len而不是空字符判断结束.
2.5 兼容部分C字符串函数
Redis设计与实现 (一): 简单动态字符串的更多相关文章
- 跟着大彬读源码 - Redis 7 - 对象编码之简单动态字符串
Redis 没有直接使用 C 语言传统的字符串表示(以空字符串结尾的字符数组),而是构建了一种名为简单动态字符串(simple dynamic string)的抽象类型,并将 SDS 用作 Redis ...
- redis 系列3 数据结构之简单动态字符串 SDS
一. SDS概述 Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默 ...
- Redis源码阅读一:简单动态字符串SDS
源码阅读基于Redis4.0.9 SDS介绍 redis 127.0.0.1:6379> SET dbname redis OK redis 127.0.0.1:6379> GET dbn ...
- redis源码学习_简单动态字符串
SDS相比传统C语言的字符串有以下好处: (1)空间预分配和惰性释放,这就可以减少内存重新分配的次数 (2)O(1)的时间复杂度获取字符串的长度 (3)二进制安全 主要总结一下sds.c和sds.h中 ...
- redis 笔记01 简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表
文中内容摘自<redis设计与实现> 简单动态字符串 1. Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS(Simple Dynamic String,简单动态 ...
- 简单动态字符串(SDS)
SDS 前提:在redis中,C字符串只会作为字符串字面量用在一些无须对字符串进行修改的地方,比如打印日志: redisLog(REDIS_WARNING, “Redis is ready to ex ...
- 《redis 5设计与源码分析》:第二章 简单动态字符串
介绍 简单动态字符串(Simple Dynamic Strings, SDS)是Redis的基本数据结构之一,用于存储字符串和整型数据.它的特点是:方便扩容.二进制安全. 二进制安全 在C语言中,用& ...
- 《Redis设计与实现》阅读笔记(二)--简单动态字符串
简单动态字符串 Redis只在一些无需对字符串进行修改的地方使用C字符串,大部分时候使用简单动态字符串(simple dynamic string, SDS),字符串的抽象类型.二进制安全,可以存放任 ...
- Redis设计与实现读书笔记——简单动态字符串
前言 项目里用到了redis数据结构,不想只是简单的调用api,这里对我的读书笔记做一下记录.原文地址: http://www.redisbook.com/en/latest/internal-dat ...
随机推荐
- 存在单点故障的namenode宕机恢复测试
前提:如果namenode没有做HA,那么至少应该启用secondarynamenode,以便namenode宕机之后手动恢复数据 实验环境:3个节点(cenos 6.10) 测试前数据: 1.为了确 ...
- GPU:并行计算利器
http://blog.jobbole.com/87849/ 首页 最新文章 IT 职场 前端 后端 移动端 数据库 运维 其他技术 - 导航条 - 首页 最新文章 IT 职场 前端 - Ja ...
- ES6 随记(3.4.1)-- 函数的拓展(参数默认值,扩展运算符)
上一章请见: 1. ES6 随记(1)-- let 与 const 2. ES6 随记(2)-- 解构赋值 3. ES6 随记(3.1)-- 字符串的拓展 4. ES6 随记(3.2)-- 正则的拓展 ...
- C++ string 用法总结
string查找替换.分割字符串.比较.截取.类型转换.排序等功能都提供了强大的处理函数,可以代替字符数组来使用. 熟练掌握好string的各种使用方法,能极大的提高编程效率哦 ^_^. #inclu ...
- Python 之 matplotlib (十六)Animation动画【转】
本文转载自:https://blog.csdn.net/wangsiji_buaa/article/details/80057875 代码: import matplotlib.pyplot as ...
- java/kotlin 读取文件、写入文件
package dh.btb.backend.utils import java.io.*object FileUtil { /** * 创建文件 * @param filePath 文件路径(不要以 ...
- unidbnavigator提示汉化
- TypeScript 教程&手册
参考:https://www.w3cschool.cn/typescript/ https://www.gitbook.com/book/zhongsp/typescript-handbook/det ...
- 用WebClient在异步下载或上传时每次只进行一个任务 C#
当在每次上传或者下载的时候,我只想进行一个任务的,我用的是WebClient类,但是我又不想用同步的方法UploadFile.DownloadFile,因为WebClient这个类的同步方法没有Upl ...
- Java多线程编程总结
Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调 ...