Redis—简单动态字符串(SDS)
Redis—简单动态字符串(SDS)
这两天我原本打算学习一下若依这个老生常谈的开源的后端管理系统(如果你没听过,在将来的某一天也会听说甚至用到),拿到这个系统的前后端分离版后,若依码云项目地址,一启动发现需要Redis服务,遂转战学习Redis(Redis也是老生常谈了~)
白泽预计将花费一个月的时间去学习Redis的设计与实现,并尽量保证文章的输出,我们共勉~
本次介绍一个Redis的数据类型,简单动态字符串,SDS(simple dynamic string),因为Redis是用C语言写的,而且C语言本身就有字符串这个数据类型,那就要提出疑问:为啥不直接用C语言的字符串,而要新发明一种新的字符串类型呢?
事实上,即使我没学过Redis,也听闻过它可以以键值对的形式存储数据,它很快。但它的快绝不仅仅是键值对的存储形式带来的,SDS的存在就是帮助Redis更快,更安全~
SDS的定义
//sds的存储结构
struct sdshdr {
int len; //记录buf数组中已经使用的字节的数量
int free; //记录buf数组中还未使用的字节的数量
char buf[]; //字节数组,用于保存字符串
};
很明显,SDS内部就是一个C语言的字符串(字节数组),只是多了两个变量存放当前的长度和剩余的长度,下面这张图模拟了当sds存放了 'Redis' 字符串后的情况
SDS遵循C字符串以空字符结尾的惯例,保存空字符的1字节空间不计算在SDS的len属性中,好处是SDS可以直接重用一部分的C字符串函数库中的函数(只要SDS内部的buf也是以'\0'结尾,那就是一个C语言的字符串啊,有啥不能用的~)

当然还可以像下面这张图这样,5为已使用的buf数组的长度,5为未使用的数组的长度,而下面这种场景才是更多的出现在Redis中的。接下来就讲讲通过free,len和C语言字符串buf的配合,如何使Redis比单纯使用C语言的字符串更快,更安全吧

SDS与C字符串的区别
1. 常数复杂度获取字符串长度:
因为SDS的free直接就记录了buf数组的使用长度,因此如果要获取buf的长度,SDS只需要O(1)的时间复杂度,而C的字符串需要O(N),因此更快!
2. 杜绝缓冲区溢出:

如上图:因为C语言字符串不记录本身的长度,如果原本连续的内存中存放了str1 = 'Redis',str2 = 'MySQL'两个字符串,此时执行某个操作将str1替换为下方的str1 = 'Hello BaiZe',那么str1的内容将会溢出到原本str2的空间中
如果使用SDS的API修改SDS内容时,如果buf剩余空间不足,API将先扩容SDS的空间,然后再修改buf数组的内容。因此更安全!
3. 减少修改字符串时带来的内存重分配次数
C语言的字符串无论是增长还是缩短,每次都需要程序重新分配内存(因为可能会影响到内存已经存在的数据),这就意味着每次都将消耗一定资源去完成这个任务。
而Redis作为数据库,数据可能会频繁修改,每次都去内存重分配就慢了。而在SDS中,len、free和buf数组相配合,就能从两个角度去优化频繁修改时时间的消耗
空间预分配:
当SDS需要扩容的时候(进行一次内存重新分配),扩容后len小于1MB,那么程序分配和len属性相同大小的free空间,则本次扩容后SDS的free会等于此时SDS的len,当然空字符'\0'依旧会占额外的一字节的空间,本次扩容结束后SDS所占空间为:len + free + 1byte
如果扩容后len大于1MB,那么程序会分配1MB的未使用free空间(所以最多就是给你分配1MB的free),此时SDS所占用空间为:len + free(1MB) + 1byte
说到底空间预分配的目的就是每次扩容时多申请一些空间(每次扩容也是一次内存的重新分配),以备下次buf数组长度增长时或许可以不去申请内存的重新分配,但最差的情况下每次多申请的空间都不够下次用的,那依旧退化为C语言字符串扩容时每次都需要重新分配内存的情况
惰性空间释放
有扩容就有缩短,当SDS的buf变短时,程序并不直接进行内存的重新分配,而是只是增加free的值,这比进行一次内存重新分配缩短buf快很多!buf数组多余的5个空间依旧保留,如果将来要对SDS进行增长操作还能用上。当然如果有需要SDS也提供了API对这些空间进行真正的释放


4. 二进制安全
C语言字符串以空字符'\0'判断字符串是否结束,那么下面这种含有两个空字符的字符串就无法完整地存入C语言的字符串,因此也无法存储二进制数据(图片、视频、音频等),但是SDS的长度是由len定义的,因此内部也可以存放空字符'\0',也可以用于保存二进制数据(啥都能存)

小结
C字符串和SDS的区别

Redis—简单动态字符串(SDS)的更多相关文章
- 图解Redis之数据结构篇——简单动态字符串SDS
图解Redis之数据结构篇--简单动态字符串SDS 前言 相信用过Redis的人都知道,Redis提供了一个逻辑上的对象系统构建了一个键值对数据库以供客户端用户使用.这个对象系统包括字符串对象 ...
- Redis底层探秘(一):简单动态字符串(SDS)
redis是我们使用非常多的一种缓存技术,他的性能极高,读的速度是110000次/s,写的速度是81000次/s.这么高的性能背后,到底是怎么样的实现在支撑,这个系列的文章,我们一起去看看. redi ...
- Redis数据结构之简单动态字符串SDS
Redis的底层数据结构非常多,其中包括SDS.ZipList.SkipList.LinkedList.HashTable.Intset等.如果你对Redis的理解还只停留在get.set的水平的话, ...
- redis 系列3 数据结构之简单动态字符串 SDS
一. SDS概述 Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默 ...
- Redis源码解析:01简单动态字符串SDS
Redis没有直接使用C字符串(以'\0'结尾的字符数组),而是构建了一种名为简单动态字符串( simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默认字符 ...
- Redis核心原理-简单动态字符串SDS
SDS简介 Redis是C语言编写的,但没有使用c语言的字符串结构,而是自己实现了一套简单动态字符串 simple dynamic string 简称SDS,SDS兼容C语言的字符串类型,原理类似Ja ...
- 深入理解Redis 数据结构—简单动态字符串sds
Redis是用ANSI C语言编写的,它是一个高性能的key-value数据库,它可以作用在数据库.缓存和消息中间件.其中 Redis 键值对中的键都是 string 类型,而键值对中的值也是有 st ...
- 【Redis】简单动态字符串SDS
C语言字符串 char *str = "redis"; // 可以不显式的添加\0,由编译器添加 char *str = "redis\0"; // 也可以添加 ...
- Redis5设计与源码分析读后感(二)简单动态字符串SDS
一.引言 学习之前先了解几个概念: SDS定义:简单动态字符串,Redis的基本数据结构之一,用于储存字符串和整型数据. 二进制安全:C语言中用"\0"表示字符串结束,如果字符串本 ...
随机推荐
- 死磕Spring之IoC篇 - Spring 应用上下文 ApplicationContext
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- python工业互联网应用实战8—django-simpleui
笔者也使用过一段时间adminx组件,后来由于adminx停更,又遇到更简单的django-simpleui后,现在基本上只使用simpleui了,使用simpleui的几个好处,笔者认为排在第一位的 ...
- Apache配置 7.静态元素过期时间
(1)介绍 那到底能缓存多久呢?如果服务器上的某个图片更改了,那么应该访问新的图片才对.这就涉及一个静态文件缓存时长的问题,也叫作"缓存过期时间".在httpd的配置文件中,我们是 ...
- div+伪元素实现太极图
需求:使用div和伪元素实现阴阳太极图 图例: 代码: <html> <head> <title>太极图</title> <style type= ...
- LeetCode 175. Combine Two Tables 【MySQL中连接查询on和where的区别】
一.题目 175. Combine Two Tables 二.分析 连接查询的时候要考虑where和on的区别 where : 查询时,连接的时候是必须严格满足条件的,满足了才会加入到临时表中. on ...
- 20个最有用的Python数据科学库
核心库与统计 1. NumPy(提交:17911,贡献者:641) 一般我们会将科学领域的库作为清单打头,NumPy 是该领域的主要软件库之一.它旨在处理大型的多维数组和矩阵,并提供了很多高级的数学函 ...
- 2018ICPC南京 A. Adrien and Austin
题目: 题意:1-N个石子每次只能取连续的1-K个问输赢.(一开始以为只是个简简单单的巴什游戏,激动的提交了一发wr了,再读了一遍题才发现是只能取连续的) 题解:当n==0或者k==1&&am ...
- 下载微软pdb符号文件
使用symchk.exe 逐层下载c:\windows\system32下的pdb文件 symchk /r c:\windows\system32 /s SRV*D:\mypdb\*http://m ...
- 攻防世界 resver catch-me
catch-me asis-ctf-quals-2016 附件给了个压缩包文件,重命名,解压,获取到elf文件 程序有两处关键比较 第一处: 这里进行动态调试,得到v3=0xB11924E1, byt ...
- Android学习之服务初体验
•概念 Service(服务)是一个长期运行在后台,没有用户界面的应用组件,即使切换到另一个应用程序或者后台,服务也可以正常运行: 因此,服务适合执行一些不需要显示界面的后台耗时操作,比如下载网络数据 ...